<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=utf-8">
<Meta http-equiv="Content-language" Content="zh-CN">
<title>桂林电子科技大学毕业设计说明书</title>
<link rel="stylesheet" type="text/css" href="print.css" />
<style type="text/css" media="screen">
#header {
	display: none;
}

div.article {
	border: 1px solid #ccc;
	line-height: 20pt;
	padding: 2.5cm;
}
code,pre {
	color: #007000;
	}
</style>
<style type="text/css" media="print">
#header {
	position: fixed;
	top: 0;
	text-align: center;
	text-size: small;
	padding-bottom: 3px;
}

body{
line-height: 20pt;
}
.body h2 {
	page-break-before:always;
}
.body h2.intro{page-break-before:none;}

.section_name {
	font-size:14pt;
	font-family:"黑体";
}

.sub_section_name {
	font-size:12pt;
	font-family:"黑体";
}

.sub_sub_section_name {
	font-size:12pt;
	font-family:"楷体";
}
</style>
<style>

.section_name {
	font-size:14pt;
	font-family:"黑体";
}

.sub_section_name {
	font-size:12pt;
	font-family:"黑体";
}

.sub_sub_section_name {
	font-size:12pt;
	font-family:"楷体";
}



span.section_name,span.sub_section_name,span.sub_sub_section_name {
	width: 16cm;
	overflow: hidden;
}
/** span.section_name:after{content:"…………………………………";}
              span.sub_section_name:after{content:"…………………………………";}
              span.sub_sub_section_name:after{content:"…………………………………";}**/

/*** body **/
body {
	width: 21cm;
	margin-left: auto;
	margin-right: auto;
	font-size:12pt;
	font-family:"宋体";
}

h2+div,h3+div,h4+div,h5+div,h6+div {
	text-indent: 2em;
}

p {
	text-indent: 2em;
}

code,pre {
	font-family: monospace;
	line-height: 1em;
}

pre {
	border: 1px solid #ccc;
	background-color: #fafafa;
	padding: 10px;
	margin: 0 0 1em 1em;
	overflow: auto;
	line-height: inherit;
	font-family: monospace;
}

/*** references **/
.cite_list li {
	list-style: none;
}
li.long_cite{display:table-row;}
span.long_cite,li.long_cite cite{display:table-cell;}
pre {
	text-align: left;
}
div.img_wrapper{text-align:center;}
p.pic_desc{	font-size: 10.5pt;
	font-family:"黑体";font-weight: bold;}
cite.zh{font-size: 10.5pt;
	font-family:"宋体";}
	cite.en{	font-size: 10.5pt;
	font-family: "Times New Roman";font-style:normal;}
</style>
</head>

<body>
	<div class="article">
				<section>
				<h2 class="intro section_name">引言</h2>

				<p>在移动智能操作系统中，在国外市场中，2012年5月15日凤凰科技报道，在澳大利亚、英国、法国、德国、意大利、西班牙和美国等七个主要市场，
				Android的市场份额在截至4月中旬的12个星期里增长强劲。在西班牙和意大利。
				Android的市场份额同比增长了一倍多，分别达到72%和49%；在德国，这款操作系统的市场份额也增长了近一倍，达到62%。<sup>[12]</sup>
				</p>
				<p>
				 而在国内市场：
				 从商务部公告2012年第25号 关于附加限制性条件批准谷歌收购摩托罗拉移动经营者集中反垄断审查决定的公告<sup>[13]</sup>
				 中也有提到"2011年第四季度，仅谷歌开发的安卓系统就占据73.99%中国市场份额"
				 </p>
                  <p>Android系统能够成为市场份额第一的智能移动操作系统，与其出色的系统性能，开放性，移植性，支持设备众多分不开。
                   以往的各种嵌入式设备应用，都在向Android平台转移。本文就是在这一背景下出现的。
                   在Android之前一些餐厅就有使用无线PDA占菜系统。这些系统很多是基于Windows CE系统，而这个系统现在已经被它的开发商微软放弃。
                   所以，我们决定开发基于Android平台的无线点菜系统。Android本身的无线通信能力比其它以往设备更出色。基于Android平台的更多应用也将出现。
                  将应用向android平台移植是大势所趋。
                  </p>
                  <p>
                  	本文主要介绍了开发这样一个无线点菜应用所要涉及到的Android开发技术，设计上需要思考的问题及解决方案，容易遇到的问题及解决方案。
                  	另外本文还对软件开发方面重构这一能够有效代码设计，软件设计的技术做了实践及探讨。
                  </p>
                  <p>
                   本文同时对如何提高应用的性能方面，对设备的兼容性方面，做了探讨。
                  </p>
				
			</section>
		<div class="body">
			<section class="wlan">
				<h2 class="section_name">1&nbsp;&nbsp;基础理论之：无线局域网及网络通信</h2>
				<div class="sub_section">
					<h3 class="sub_section_name">1.1&nbsp;无线局域网</h3>
					<p>
					来自维基百科的解释如下<sup>[2]</sup>：
					<blocksquote> 无线局域网（Wireless LAN,
					WLAN）（以下简称WLAN)是不使用任何导线或传输电缆连接的局域网，而使用无线电波作为数据传送的媒介，传送距离一般只有几十米。无线局域网的主干网路通常使用有线电缆（Cable），无线局域网用户通过一个或多个无线接取器（Wireless
					Access Points, WAP）接入无线局域网。 </blocksquote>
					</p>
				<div class="sub_sub_section">
						<h4 class="sub_sub_section_name">1.1.1&nbsp;技术特点</h4>
						<p>
							无线局域网第一个版本发表于1997年，其中定义了介质访问接入控制层（MAC层）和物理层。物理层定义了工作在2.4GHz的ISM频段上的两种无线调频方式和一种红外传输的方式，总数据传输速率设计为2Mbit/s。两个设备之间的通信可以自由直接(ad
							hoc)的方式进行，也可以在基站(Base Station, BS)或者访问点（Access Point，AP）的协调下进行。</p>
						<p>1999年，加上了两个补充版本: 802.11a定义了一个在5GHz
							ISM频段上的数据传输速率可达54Mbit/s的物理层，802.11b定义了一个在2.4GHz的ISM频段上但数据传输速率高达11Mbit/s的物理层。
							2.4GHz的ISM频段为世界上绝大多数国家通用，因此802.11b得到了最为广泛的应用。苹果公司把自己开发的802.11标准起名叫AirPort。1999年工业界成立了Wi-Fi联盟，致力解决符合802.11标准的产品的生产和设备兼容性问题。
							802.11标准和补充。</p>
							<p>
								802.11有两种基础的操作模式：ad-hoc模式和基础架构模式。在ad-hoc模式中，移动设备单位直接点对点的传输。
								在基础架构模式下，移动设备单位通过一个访问点进行通信，访问点充当与有线网络架构的连接桥。因为相比有线连接而言无线通信使用了开放的连接介质，802.11的设计者们同样考虑了共享密钥加密机制:Wired
								Equivalent Privacy(WEP),Wi-Fi Protected
								Access(WPA,WPA2),来保证无线网络连接的安全性。</p>
				</div><!-- end of 1.1.1 -->
				
				
					<div class="sub_sub_section">
						<h4 class="sub_sub_section_name">1.1.2&nbsp;WLAN的优点及不足之处</h4>
						优点如下：
						<ol>
							<li>灵活性和移动性。无线局域网在无线信号覆盖区域内的任何一个位置都可以接入网络。</li>
							<li>安装便捷，易于进行网络规划和调整。无线局域网可以免去或最大程度地减少网络布线的工作量，一般只要安装一个或多个接入点设备，就可建立覆盖整个区域的局域网络。</li>
							<li>故障定位容易。无线网络容易定位故障，只需更换故障设备即可恢复网络连接。</li>
							<li>易于扩展。无线局域网有多种配置方式，可以很快从只有几个用户的小型局域网扩展到上千用户的大型网络，并且能够提供节点间“漫游”等有线网络无法实现的特性。</li>
						</ol>
						不足：
						<ol>
							<li>性能。无线局域网是依靠无线电波进行传输的。这些电波通过无线发射装置进行发射，而建筑物、车辆、树木和其它障碍物都可能阻碍电磁波的传输，所以会影响网络的性能。</li>
							<li>速率。无线信道的传输速率与有线信道相比要低得多。目前，无线局域网的最大传输速率为150Mbit/s，只适合于个人终端和小规模网络应用。</li>
							<li>安全性。本质上无线电波不要求建立物理的连接通道，无线信号是发散的。从理论上讲，很容易监听到无线电波广播范围内的任何信号，造成通信信息泄漏。</li>

						</ol>
					</div>
					<!-- end of 1.1.2 -->

					<div class="sub_sub_section">
						<h4 class="sub_sub_section_name">1.1.3&nbsp;WLAN常见应用场景</h4>
						<ul>
							<li><strong>大楼之间：</strong>
								大楼之间建构网络的连结，取代专线，简单又便宜。</li>
							<li><strong>餐饮及零售：</strong>
								餐饮服务业可使用无线局域网络产品，直接从餐桌即可输入并传送客人点菜内容至厨房、柜台。零售商促销时，可使用无线局域网络产品设置临时收银柜台。
							</li>
							<li><strong>医疗：</strong>
								使用附无线局域网络产品的手提式计算机取得实时信息，医护人员可藉此避免对伤患救治的迟延、不必要的纸上作业、单据循环的迟延及误诊等，而提升对伤患照顾的品质
							</li>
							<li><strong>展示会场：</strong>
							诸如一般的电子展，计算机展，由于网络需求极高，而且布线又会让会场显得凌乱，因此若能使用无线网络，则是再好不过的选择。
							</li>
						</ul>

					</div>
					<!-- end of 1.1.3 -->

					<div class="sub_sub_section">
						<h4 class="sub_sub_section_name">1.1.4&nbsp;常见的简单的组建无线局域网的方案</h4>
						<div>
							<h5>简单的家庭WLAN</h5>
							<p>
								一般来说只要一个无线路由器就可以了。其它带有无线网卡的设备可以通过此无线路由组建一个简单的无线局域网。
								通过将无线路由器与因特网连接，就可以在家庭内部共享网络连接了。如下图所示：
													<div class="img_wrapper">
													<img src="drawables/home_wlan.jpg" title="home_wlan" />
													<p class="pic_desc">图&nbsp;1.1&nbsp;简单的家庭WLAN示意图</p>
													</div>
								一台设备作为防火墙，路由器，交换机和无线接入点。这些无线路由器可以提供广泛的功能，
								例如：保护家庭网络远离外界的入侵。允许共享一个ISP（Internet服务提供商）的单一IP地址。可为4台计算机提供有线以太网服务，
								但是也可以和另一个以太网交换机或集线器进行扩展。为多个无线计算机作一个无线接入点。
								通常基本模块提供2.4GHz802.11b/g操作的Wi-Fi。
						         <sup>[1]</sup>
							</p>
						</div>
						<div>
							<h5>无线桥接</h5>
							<p>
								当有线连接以太网或者需要为有线连接建立第二条冗余连接以作备份时，无线桥接允许在建筑物之间进行无线连接。
								802.11设备通常用来进行这项应用以及无线光纤桥。802.11基本解决方案一般更便宜并且不需要在天线之间有直视性，
								但是比光纤解决方案要慢很多。802.11解决方案通常在5至30mbps范围内操作，而光纤解决方案在100至1000mbps范围内操作。
								这两种桥操作距离可以超过10英里，基于802.11的解决方案可达到这个距离，而且它不需要线缆连接。
								但基于802.11的解决方案的缺点是速度慢和存在干扰，而光纤解决方案不会。
								光纤解决方案的缺点是价格高以及两个地点间不具有直视性。<sup>[1]</sup>
							
							</p>
						</div>
						<div>
							<h5 >点对点直接通信</h5>
							<p>WLAN无线通信也可以直接不需通过接入点传出从一台电脑到另一台。这就是所谓的Ad -
								hoc模式的WLAN传输。这种无线ad -
								hoc网络模式已经证明多人的欢迎，掌上游戏机，如任天堂的DS，数码相机和其它消费电子设备。</p>
						</div>
					</div>
					<!-- end of 1.1.4 -->
					
					<div />
					<!-- end 1.1 -->

					<div class="sub_section Wi-Fi">
						<h3 class="sub_section_name">
						1.2&nbsp;Wi-Fi<sup>[4]</sup></h3>
					    			<p>Wi-Fi是Wi-Fi联盟制造商的商标可做为产品的品牌认证，是一个建立于IEEE
					802.11标准的无线局域网络（WLAN）设备。基于两套系统的密切相关，也常有人把Wi-Fi当做IEEE
					802.11标准的同义词术语。</p>
						<p>IEEE
					802.11的设备已安装在市面上的许多产品，如个人电脑，游戏机，MP3播放器，智慧型手机，打印机以及其他周边设备，和新笔记型电脑。</p>
					
						
						<div class="sub_sub_section">
							<h4 class="sub_sub_section_name">
								1.2.1&nbsp;工作原理<sup>[4]</sup>
							</h4>
							<p>Wi-Fi的设置至少需要一个Access
								Point（ap）和一个或一个以上的client（hi）。AP每100ms将SSID（Service Set
								Identifier）经由beacons（信号台）封包广播一次，beacons封包的传输速率是1
								Mbit/s，并且长度相当的短，所以这个广播动作对网络效能的影响不大。因为Wi-Fi规定的最低传输速率是1
								Mbit/s，所以确保所有的Wi-Fi
								client端都能收到这个SSID广播封包，client可以借此决定是否要和这一个SSID的AP连线。使用者可以设定要连线到哪一个SSID。
								Wi-Fi系统总是对用户端开放其连接标准，并支援漫游，这就是Wi-Fi的好处。但亦意味着，一个无线适配器有可能在性能上优于其他的适配器。
								由于Wi-Fi通过空气传送信号，所以和非交换以太网有相同的特点。</p>
						</div>
						<!-- end of 1.2.1 -->
						<div class="sub_sub_section">
							<h4 class="sub_sub_section_name">
								1.2.2&nbsp;优势和挑战
							</h4>
							<p>
							Wi-Fi作为WLAN标准的一一种具体技术协议具有WLAN的优点。
							Wi-Fi部署区网（LAN）可让客户端设备无需使用电线，通常可降网络部署和扩充的成本。许多空间不能架设电缆，如户外区和历史建筑，可运用无线区网来改善。
							但是也也存在一些限制，如传递的距离有限。
							</p>
							<p>
										Wi-Fi网络范围有限。
										一般无线路由产生的信号覆盖范围大概是室内50平方米，室外140平方米，
										典型Wi-Fi的频率由于电波传播的复杂性，特别是树和建筑物影响信号的反射，
										大约只能预测出Wi-Fi有关任何地区的发射器的信号强度。这不适用于远距离的Wi-Fi，
										因为远距离Wi-Fi是使用塔台或高建筑顶上的天线所架设的。
									Wi-Fi的应用基本上实用范围非常有限所如；仓库中或零售空间的盘点机，结帐条码阅读器
									，或收发台。为达到无线区网的应用要求，比起其他一些标准Wi-Fi相当的耗电。<sup>[4]</sup>
							</p>
						</div>
						<!-- end of 1.2.2 -->
				
					
					</div><!-- end 1.2 -->
					
					
					<div class="sub_section bluetooth_wifi_direct">
						<h3 class="sub_section_name">
						1.3&nbsp;蓝牙及其它<sup>[5]</sup>
						</h3>
						<p>
							组建局域网的技术除了上面提到了Wi-Fi家族技术。蓝牙也可以算得上一一种。虽然蓝牙相对来说就是用来进行无线通信，
				甚至不是很少人认为它是用来组建网络的。
						</p>
						<div class="sub_sub_section">
							<h4 class="sub_sub_section_name">
								1.3.1&nbsp;蓝牙的历史<sup>[5]</sup>
							</h4>
							<p>
								蓝牙技术最初由爱立信创制。技术始于爱立信公司的1994方案，1999年5月20日，索尼易立信、国际商业机器、英特尔、诺基亚及东芝公司等业界龙头创立“特别兴趣小组”（Special
								Interest Group，SIG），即蓝牙技术联盟的前身，目标是开发一个成本低、效益高、可以在短距离范围内随意无线连接的蓝牙技术标准。</p>
			
							<p>
								2001年的1.1版正式列入IEEE标准，Bluetooth
								1.1即为IEEE
								802.15.1。同年，SIG成员公司超过2000家。为了扩宽蓝牙的应用层面和传输速度，SIG先后推出了1.2、2.0版，以及其他附加新功能，例如EDR（Enhanced
								Data Rate，配合2.0的技术标准，将最大传输速度提高到3Mbps）、A2DP（Advanced Audio
								Distribution Profile，一个控音轨分配技术，主要应用于立体声耳机）、AVRCP（A/V Remote
								Control Profile）等。Bluetooth
								2.0将传输率提升至2Mbps、3Mbps，远大于1.x版的1Mbps（实际约723.2kbps）。</p>
		
						</div>
						<!-- end of 3.1 -->
		
		
						<div class="sub_sub_section">
							<h4 class="sub_sub_section_name">
								1.3.2&nbsp;蓝牙应用<sup>[5]</sup>
							</h4>
							<p>
								移动电话和免提设备之间的无线通讯,这也是最初流行的应用；
								特定距离内电脑间的无线网络；
								电脑与外设的无线连接,如:鼠标,耳麦,打印机等；
								蓝牙设备之间的文件传输；
							传统有线设备的无线化,如:医用器材,GPS,条形码扫描仪,交管设备；
								数个以太网之间的无线桥架；
								7代家用游戏机的手柄, PS3PSP go, NitendoWii。
							</p>
						</div>
						<!-- end of 1.3.2 -->
						
						<div class="sub_sub_section">
							<h4 class="sub_sub_section_name">1.3.3&nbsp;Wi-Fi&nbsp;Direct</h4>
							<p>
							2010年10月，Wi-Fi Alliance（wi-fi联盟）发布Wi-Fi Direct白皮书，白皮书中介绍了关于这种技术的基本信息、
							这种技术的特点和这种技术的功能，Wi-Fi Direct标准是指允许无线网络中的设备无需通过无线路由器即可相互连接。
							与蓝牙技术类似，这种标准允许无线设备以点对点形式互连，不过在传输速度与传输距离方面则比蓝牙有大幅提升。
							</p>
						</div>
						
					</div><!--  end of 1.3  -->





			</section><!--  end of  section 1  -->




			<section class="android">
				<h2 class="section_name">2&nbsp;&nbsp;基础理论之：Android</h2>
								 <p>
				 Android（读音：['ændrɔid]）是一个以Linux为基础的半开源操作系统，主要用于行动设备，由Google和开放手持设备联盟开发与领导。
Android 系统最初由安迪·鲁宾（Andy Rubin）制作，最初主要支持手机。2005年8月17日被Google收购。
2007年11月5日，Google与84家硬件制造商、软件开发商及电信营运商组成开放手持设备联盟（Open Handset Alliance）来共同研发改良Android系统并生产搭载Android的智慧型手机，
并逐渐拓展到平板电脑及其他领域上。随后，Google以Apache免费开源许可证的授权方式，发布了Android的源代码。
        同时，一个负责进一步发展和维护Android操作系统的Android开源项目也被建立（AOSP）。<sup>[14]</sup>
				</p>
						<p>Android是一个手机设置的软件栈。包括了操作系统，中间件及关键应用程序。Android
						SDK提供了用于在Android平台使用Java语言开发应用的工具。</p>
						
				<div class="sub_section">
					<h3 class="sub_section_name">
						2.1&nbsp;Android概述<sup>[6]</sup>
					</h3>
			
									
					<div  class="sub_sub_section" data-role="collapsible" data-theme="a">
						<h4 class="sub_sub_section_name">2.1.1&nbsp;特点(Features)</h4>
						<ul>
							<li><strong>应用框架</strong> 重用及可替换的组件。</li>
							<li><strong>Dalvik虚拟机</strong> 针对手机优化</li>
							<li><strong>集成浏览器</strong> 基于开源的webkit引擎</li>
							<li><strong>优化的图形库</strong> 支持2D图形库，基于OpenGL ES
								的3D图形库。（可选的硬件加速)</li>
							<li><strong>SQLite嵌入式关系型数据库</strong> 支持结构化数据存储</li>
							<li><strong>多媒体支持</strong> 常用的音频，视频，和静态图像格式(MPEG4,
								H.264, MP3, AAC, AMR, JPG, PNG, GIF)</li>
							<li><strong>GSM</strong> (由硬件决定)</li>
							<li><strong>蓝牙, EDGE, 3G,及 WiFi,相机, GPS, 罗盘,重力感应</strong> 取决于硬件)</li>
							<li><strong>强大的集成开发环境</strong>包含设备模拟器(emulator),调试工具，内存及性能分析工具，Eclipse IDE插件。</li>
						</ul>
					</div>
					<!-- end of collaspside  2.1.1-->
					<div class="sub_sub_section" data-role="collapsible" data-theme="a">
						<h4 class="sub_sub_section_name">2.1.2&nbsp;android体系结构(Android
							Architecture)</h4>
						<p>下面这张图示展示了Android 操作系统的主要部件：</p>
											<div class="img_wrapper">
				<img src="drawables/system-architecture.jpg"  height="300" />
					<p class="pic_desc">图&nbsp;2.1&nbsp;Android体系结构示意图</p>
					</div>
						

					</div>
					<!-- end of collaspside 2.1.2 -->
					<div class="sub_sub_section" data-role="collapsible" data-theme="a">
						<h4 class="sub_sub_section_name">2.1.3&nbsp;应用及应用框架</h4>
						<p>android系统自带了一系统核心应用，包含email客户端，SMS客户端，日历，浏览器，联系人等其它。所以程序都使用Java语言写的。
						同时，简化组件重用，包含一个服务及系统集合。
							丰富可扩展的Views（视图）集合;
							Content Providers用于在应用间共享数据;
							通知管理器(Notification Manager)在状态条中显示自定义的通知警告;
							活动管理器(Activity Manager)管理应用的生命周期，并提供一个通用的后退导航栈。
						</p>
					</div>
					<!-- end of collaspside 2.1.3 -->
					
				<div   class="sub_sub_section" data-role="collapsible" data-theme="a">
						<h4 class="sub_sub_section_name">2.1.4&nbsp;Android运行时(Android Runtime）</h4>
						<p>
							android提供了Java编程语言使用的基本核心库，每一个android应用都在自己的进程中运行，并且有它自己的Dalvik虚拟机实例。
							Dalvik设计使得能够高效运行多个虚拟机。.dex文件，优化成最小化内存使用。虚拟机是基于寄存器的。由Java类文件用"dx"工具转换而来。
							Dalvik虚拟机依赖于Linux内核来处理于线程和低内存管理。
						</p>
					</div>
					<div   class="sub_sub_section" data-role="collapsible" data-theme="a">
						<h4 class="sub_sub_section_name">2.1.5&nbsp;Linux内核（Linux Kernerl）</h4>
						<p>
							Android基于Linux版本2.6（android4开始基于3.x，后缀android版本内核版本可能更新）的内核
							来处理如系统服务，安全管理，内内在管理，进程管理，网络栈，驱动模型。内核同样是在硬件与软件栈之间的抽象层！</p>
					</div>
					
					
				</div><!--  end of 2.1 -->	
				
				<div class="sub_section">
					<h3 class="sub_section_name">
						2.2&nbsp;Android基本构架（application fundamentals)<sup>[7]</sup>
					</h3>
					<p>android程序以java语言编写，.apk作为后缀的安装包文件。里面还包含了其它的 资源文件。
						在设备上安装了的程序在它自己的沙箱中运行。</p>
					<div   class="sub_sub_section"  data-role="collapsible" data-theme="a">
						<h4 class="sub_sub_section_name">2.2.1&nbsp;基本特点</h4>
						<ul>
							<li>linux 每一个程序以不用的用户运行</li>
							<li>系统为每一个程序设置一个唯一的ID,此ID对程序不可见。系统为应用程序设置权限，拥有ID的的应用才能访问相应文件。</li>
							<li>每一个进程都有自己的虚拟机。</li>
							<li>默认下每一个应用都在它自己的linux进程中运行。程序某部件需要执行时Android启动此进程，如果以进程不在需要或者系统需要回收内存时，此系统将关闭。</li>
							<li>android系统,应用，符合"最小权限原则",</li>
							
						</ul>
						android中的应用可以通过下面的 方式在应用程序地共享数据或者访问系统服务。 1.可以让两个应用共享同一个LINUX
						用户ID。这可以让应用运行在同一个linux进程及虚拟机当中。注意这需要应用有相同的证书。 2.
						在安装时经过用户的许可。应用可以访问设备的数据，如通讯录，SMS信息。可挂载存在设置（sd卡),相机，蓝牙等等。


					</div>
					<!--  end of 基本特点    2.2.1 -->

					<div    class="sub_sub_section"  data-role="collapsible" data-theme="a">
						<h4 class="sub_sub_section_name">2.2.2&nbsp;应用程序组件</h4>
						<p>四个不同组件</p>
						<ul>
							<li>
							<strong>活动（Activities)</strong>
							一个活动－一个单独与用户交互的屏幕单位。
								如果程序允许，一个程序的活动可以被另一个程序启A动。
								作为android.app.Activity的子类来实现
						</li>
						<li>
							<strong>服务 （Services)</strong>
								服务是在后台执行以便执行一些长时间运行的操作或者为远程线程操作。一个服务并不提供一个用户界面。
								一个服务可以绑定一个活动来实现某些用户交互。
						</li>
						<li>
							<strong>
								内容提供者（Content providers)
								</strong>
								内容提供者管理应用程序共享的数据，可以为应用选择地将数据存在在文件系统中，或者SQLite数据库中，
								互联网或者其它存储地方。通过内容提供都其它应用可以查询或者修改这些数据（如果内容提供都允许。）
									（例如Android系统提供了一个内容提供者来管理用户联系人信息。ContactsContract.Data）
						</li>
						<li>
							<strong>广播接收者(Broadcast receviers)</strong>
							广播接收者来处理系统范围内的广播（如电量过低，屏幕过低。应用程序也能够发起广播。
							虽然他们不显示用户界面，当有广播时他们也会创建一个状态通知条来提醒用户。
							如，也许可以发起一个服务来跟发生的事件来执行某些动作。作为android.content.BroadcastRecevier的子类
						</li>
							
						</ul>
					</div>
					<!--  end of 应用程序组件  2.2.2     -->
				</div><!--  end of 2.2 -->
				
					
			</section><!--  end of section 2  -->


		<section>
			<h2 class="section_name">3&nbsp;&nbsp;开发环境搭建</h2>
			<p>开发环境搭建主要分为两点:(1)安装jdk及android sdk.(2)安装开发所需要工具如eclipse ,adt</p>
			<div class="ui-body ui-body-a">
				<h3 class="sub_section_name">
					3.1&nbsp;安装Android SDK<sup>[10]</sup></sup>
				</h3>
				<p>这里要注意的是，如果已经安装有SDK了，那么应该选择升级而不是重新安装。</p>
				<div data-role="collapsible" data-theme="a">
					<h4>第一步:准备开发电脑</h4>
					<p>首先确认你的电脑满足开发的系统需要。
					</p>
					<ul>
						<li>Windows XP(32位)，Vista(32或者64位)，Windows 7(32或者64位)</li>
						<li>Mac OS X 10.5.8或者更新(仅支持x86架构)</li>
						<li>Linux（推荐使用Ubuntu 10.04+，8.04+也可以）（如果是64位系统的话，需要保证能运行32位程序）</li>
					</ul>
				</div>

				<div data-role="collapsible" data-theme="a">
					<h4>第二步:下载sdk初始包。</h4>
					<p>
						SDK初始包并没有包含完全的开发环境。仅包含核心的工具。你可以通过这些工具来下载安装其它必要的工具。
						（例如最新的android平台),如果是.zip或者.tgz包的话解压，.exe包的话点击运行，运行时会先检查jdk是是否已经安装。然后再安装。
						默认的安装目录名为android-sdk-
						<machine-platform>的形式 
					</p>
				</div>
				<div data-role="collapsible" data-theme="a">
					<h4>第三步;添加平台及其它部件</h4>
					<div>
						为你的开发环境下载安装必要的sdk部件。可以以下面的方式启动android SDK和AVD Manager
						<ul>
							<li>从eclipse中选择Window | android SDK and AVD Manager</li>
							<li>在windows平台双击SDK Manager.exe 在android SDK的根目录</li>
							<li>在苹果或者linux中，打开终端，切换到tools/目录，然后执行下面的命令： <code>./android</code>
							</li>
						</ul>
					</div>
				</div>
				<div data-role="collapsible" data-theme="a">
					<h4>可用的部件（available components)</h4>
					<p>默认情况下有两个仓库在sdk目录中 一个是android repository,另一个是第三方扩展 android
						repository 提供了如下的部件：
					<ul>
						<li>SDK 工具：包含调试测试程序及其它实用工具，通过android sdk starter
							package安装，可以在tools/目录下找到。</li>
						<li>SDK平台工具:包含调试开发程序与平台有关的工具。（注意此平台是指android平台)</li>
						<li>android平台：每一个sdk平台部件都包含了一个完全的android 库，系统镜像，示例代码，模拟器皮肤等。</li>
						<li>usb driver for
							windows如果你使用windows来在android设备上调试则需要这些驱动,如果使用Mac OS X
							或者linux则不需要。 参见:Using Hardware Devices。</li>
						<li>示例(Samples)：包含各平台的示例代码及程序。</li>
						<li>文档:包含一个本地最新的多版本android 框架api文档。</li>
					</ul>
					第三方包，允许你创建使用特殊库包的项目，或者自定义的android系统镜像。
					</p>
				</div>

				<div data-role="collapsible" data-theme="a">
					<h4>第四步:浏览SDK</h4>
					<p>下面列表，简单说明了SDK目录中各个子目录的内容。
					<ul>

						<li>
							<code>add-ons/</code>
							一些Android开发的扩展库。
						</li>
						<li>
							<code>extras/</code>
							包含了Google提供的Android开发额外包,如在早期版本中使用后期版本API级别中的一些特性.如在android3之前使用android-support-4来使用Fragment等等.
						</li>
						<li>
							<code>docs/</code>
							developers.android.com的离线文档，也是最好的Android文档。
							
						</li>
						<li>
							<code>platform-tools/</code>
							与平台相关的工具，如 Android Debug Bridge (<code>adb</code>) ，跟目录 <code>tools/</code>
								分开来是为了方便升级支持最新的Android平台。
							
						</li>
						<li>
							<code>platforms/</code>
							包含了Android一系列的Android平台版本，每一个都在一个单独的目录。
						</li>
						<li>
							
							<code>
									<em>&lt;platform&gt;</em>/
								</code>
							平台版本目录，例如 "android-11".
								平台包含了Android框架库jar文件(<code>android.jar</code>) 
							
						</li>
						<li>
							<code>samples/</code>
							特定平台的示例代码.
						</li>
						<li>
							<code>tools/</code>
							android平台版本独立的工具。例如emulator,  Android SDK
								和 AVD Manager, <code>ddms</code>, <code>hierarchyviewer</code>
								等等. 
							
						</li>
						<li>
							<code>SDK Manager.exe</code>
							Windows下才有的。用来对SDK升级及下载一些组件。
						</li>

					</ul>

				</div>
				<!--  end step 5  -->

				<div data-role="collapsible" data-theme="a">
					<h4>第五步:设置环境变量</h4>
					<p>
						为了方便运行命令行工具,不想去输入工具的全路径,可以将
						<code>tools</code>
						路径,
						<code>platform-tools/</code>
						路径添加到你的PATH环境变量中. 根据不同的操作系统,可以使用下面的方式来设置环境变量.
					<ul>
						<li>在Windows中,右键我的电脑,选择[属性],在[高级]选项卡上,点击[环境变量]按钮,在弹出来的对话框中,在系统变量中双击Path.
							添加<code>tools</code>,<code>platform-tools/</code>路径添加到path中,注意用分号分隔.
						</li>
						<li>如果使用的是Linux系统,编辑<code>~/.bash_profile</code>或者<code>~/.bashrc</code>文件.查找设置PATH环境变量的那一行.
							添加<code>tools</code>,<code>platform-tools/</code>完整路径添加到PATH中.如果你没有找到设置路径的行,你可以添加一行:
							<pre>
export PATH=${PATH}:&lt;sdk&gt;/tools::&lt;sdk&gt;/platform-tools
						 		</pre> 注意将占位符&lt;sdk&gt;替换为实际的路径.
						</li>
						<li><code>在Mac OS X上,</code>在主目录中查找<code>.bash_profile</code>,处理方式跟Linux一样.如果还没有<code>.bash_profile</code>,则创建一个.</li>
					</ul>

					<p>
				</div>
				<!--  end step 6  -->

			</div>
			<!-- /themed container  end of 3.1-->
			<div class="sub_section">
				<h3 class="sub_section_name">3.2&nbsp;安装Eclipse及ADT</h3>
				<p>
				ADT是一个Eclipse IDE的插件。在安装ADT之前，应该已经安装了一个合适版本的Eclipse了。
				最好是在安装ADT之前，就已经安装好Android SDK了。
				</p>
				<div >
					<h4>第一步：安装Eclipse</h4>
					<p>
					    安装Eclipse前，请确保已经安装了JDK。可以从此地址下载：<code>http://www.oracle.com/technetwork/java/javase/downloads/index.html</code>
					    下载后点击安装既可，如果要安装比较老点的版本如JDK6也可以从此网站找到。
						Eclipse可以从此地址下载<code>http://www.eclipse.org/downloads/</code>，推荐下载"Eclipse Classic"，或者"java"版本，或者"RCP"版本。
						
					</p>
				</div>
				<div data-role="collapsible" data-theme="a">
					<h4>第二步:下载ADT插件</h4>
					<p>使用Eclipse本身的更新管理器来安装最新版本的ADT.一般方式如下（以英文界面为例）：</p>
					<ol>
						<li>启动Eclipsed,然后选择 Help > Install New Software....</li>
						<li>在右上角点击<strong>Add</strong></li>
						<li>在Add Repository对话框中，Name项中输入"ADT Plugin"，在Location中输入下面的URL:
							<pre>
https://dl-ssl.google.com/android/eclipse/
							</pre>
						</li>
						<li>点击OK。<q>如果在下载ADT中遇到问题时，试着将URL中的"https"换成"http"试试。(https会对传输内容加密，导致下载速度减慢)</q></li>
						<li>在Available Software对话框中，选择Developer Tools对应的单选框，并点击<strong>Next</strong></li>
						<li>点击接受License agreements，并点击<strong>Finish</strong>
							<q>如果在安装过程中，提示关于软件的autheticity和validity的话，点击<strong>OK</strong></q>
						</li>
						<li>安装完成之后重启Eclipse</li>
					</ol>
					如果在按照上面的方式还是没有安装成功的，请检查网络的连接性。可以尝试关闭防火墙。或者先下载离线安装包，然后再用Eclipse离线安装插件的方式安装。
					具体方式，略，最新离线安装如下载地址为：
					<code>http://dl.google.com/android/ADT-18.0.0.zip</code>
					
				</div>
			</div><!-- 3.2  -->
			
			<div class="sub_section">
				<h3 class="sub_section_name">3.3&nbsp;使用版本控制工具：SVN</h3>
				<p>
					选择使用SVN而不是当前如上中天的Git，是因为作为个人开发或者小组织内部开发SVN这个中央集中式的管理控制工具还是特别适合的。
					更重要的是我对SVN更熟悉。
				</p>
				<p>
					使用SVN主要有三个步骤：
					<ol>
							<li>创建仓库并导入初始项目。</li>
							<li>检出项目。</li>
							<li>提交，更新等</li>
					</ol>
				</p>
				<div >
					<h4>在Ubuntu下安装并使用SVN。</h4>
					<p>
					   Ubuntu提供了方便的版本管理工具，可以使用自己熟悉的方式来安装SVN。
					   最简单的就是在终端输入：<code>sudo apt-get install svn</code>
					   下面是简单的使用，详细使用方法，可以使用<code>svn help</code>本身的帮助系统来了解。
					</p>
					<ol>
						<li>创建仓库使用：<code>svn create /home/banxi1988/work/repos/android_project</code></li>
						<li>导入初始项目使用：<code>svn import tmp_project  file:///home/banxi1988/work/repos/android_project</code></li>
						<li>检出项目使用：<code>svn checkout file:///home/banxi1988/work/repos/android_project</code></li>
						<li>提交使用：<code>svn commit -m"message"</code> ，将文件添加到版本控制中：<code>svn add a.java</code>
						    更新使用：<code>svn update </code></li>
					</ol>
					
				</div>
				<div >
					<h4>在Windows下安装并使用SVN。</h4>
					<p>
					   Windows下，可以通过下载安装TotorsizeSVN。来使用SVN。
					   由于TotorsizeSVN是一个Windows外壳程序，所以可以在Windows资源管理器中方便用使用。
					   在一个目录，右键，就可以进行相关操作。类似上面Ubuntu中操作。
					</p>
				</div>
				<div >
					<h4>使用Google Code作为代码托管网站</h4>
					<p>
					 使用Google Code，可以让我们在能够上网的时候随时随地提交代码。首先在Google Code中创建一个项目，并选择使用SVN作为代码版本控制工具。
					 然后在本地客户端检出项目，然后就可以跟上面提到的一样来使用了。
					</p>
				</div>
				<p>SVN还有建立分支，增加标签等众多高级功能。在此不表。</p>
				
			</div><!--   3.3 -->
			<div class="sub_section">
				<h3 class="sub_section_name">3.4&nbsp;建立无线热点</h3>
				<p>
					无线局域网的通信，也是局域网通信，原则上对于上层的应用开发是透明的。也就是，
					开发的应用在局域网上可用，那么在无线局域网上一样可用。但是由于无线局域网本身的特性，还是有必要
					建立无线局域网进行开发测试。除了使用无线路由器之外，下面介绍的是在Ubuntu(11.10+)下将带无线网卡笔试本用作无线热点：
				</p>
				<p>
					打开[系统设置]->打开[网络]->然后打开[无线]选项页，选择[开启]无线。然后点击下面的[用作热点]，在点击右边的[选项]。
					在打开的对话框，在[无线]选项卡中SSID一栏填一个名字如"banxi"（没有引号）。在[IPv4设置]选项中，[方法]中选择[与其它计算机共享]。
					在[IPv6]选项卡中，设置方法为[忽略]，在[无线安全性]选项卡中，在安全性中如果选择了加密方式的话。设置一个密码。点击保存即可。
					
				</p>
				<p>在Windows中也可以有软件可以将带无线网卡的笔记本用作无线热点。</p>
			</div><!--   3.4 -->
			 
		</section>
		<!--  end of section 3  -->


		<section>
			<h2 class="section_name">4&nbsp;&nbsp;系统设计</h2>
			<div class="sub_section">
				<h3 class="sub_section_name">4.1&nbsp;设计原则</h3>
				<p>
					系统功能,归结为一句话就是:点菜。我们应用是要服务于餐厅服务员的。所以应用以模拟真实点菜过程。<br />
					主要的过程如下：[（1）选择桌子]->[（2）查找菜品]-->[(3)点菜]--[(4)后续操作（包括修改数量，价格，改口味，送厨房，给账单）]等等。
				</p>
				<p>对于开发运行于现代力智能移动操作系统上的点菜应用。当用充分利用系统特性，全面提升应用的用户体验。
					具体体现在设计则是以下几点：
				<ul>
					<li><strong>接近自然：简单自然的选择桌子功能。</strong>系统使用类似地图应用，模拟真实的餐厅餐桌布局来供服务员选择桌子。贴近服务员，方便使用。可以上下左右移动来切换可见视图。当用户需要
						切换楼层时，可以在界面拂动。这充分利用了现代智能操作系统的操作特性。</li>
					<li><strong>用户关注点聚焦：</strong>在用户点菜主界面，以很自然的方式整合服务员点菜及后续操作常用功能。带来操作性的创新，简洁体验。</li>
					<li><strong>细节：体现用户体验</strong>在各功能的细节上充分考虑服务员使用习惯，为服务员量身定做。字体，颜色等等。</li>
				</ul>
				</p>
			</div>
			<div class="sub_section">
				<h3 class="sub_section_name">4.2&nbsp;概要设计</h3>
				<p>通过对系统的分析，知道系统主要需要满足以下功能，功能示意流程图如下：</p>
					<div class="img_wrapper">
					<img src="drawables/order_dishes_work_flow.png" title="order_dishes_work_flow" />
					<p class="pic_desc">图&nbsp;4.1&nbsp;点菜系统功能示意流程图</p>
					</div>
				<p>
					下面对各主要功能进行简单的分析。
				</p>
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">连接服务器功能：检查及建立连接</h3>
					<p>
						主要流程为： 
							[1.从应用的偏好中读取服务器连接信息(host,port)]->[2.如果(host,port)错误，则弹出对话框，让用户输入服务器连接信息(host,port)]->
							[3.验证用户输入。如果输入非法，提示。否则继续。]->
							[4.根据host,port检测可连接性。]->[5.如果可以建立连接，则建立连接。否则提示用户无法建立连接。]
					</p>
				</div>
				<!--  end of 4.2.1  -->
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">登录功能</h3>
					<p>
						主要流程为： 
							[1.弹出对话框提示用户输入账号及密码。]->[2.验证用户输入。如果输入非法，提示。否则继续。]->[3.向服务器请求验证账号密码。验证成功则登录成功，继续，否则提示。]->[4.保存登录用户信息。]
						

					</p>
				</div>
				<!--  end of 4.2.2  -->
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">同步菜单数据功能</h3>
					<p>
						主要流程为：
							[1.读取应用保证的服务器数据信息(ip,host,timestamp,timestamp记录菜单数据更新的最后时间。)]->[2.如果ip或者host不同，下载菜单数据，并更新timestamp。否则继续]
							->[3.向服务器菜单数据timestamp。如果服务端的timestamp大于原来保存的timestamp。则下载菜单数据。]->[4.更新完成，提示。]
						</strong>

					</p>
				</div>
				<!--  end of 4.2.3  -->
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">在SQlite中缓存菜单数据功能</h3>
					<p>
						主要流程为：  [1.根据需要创建数据库表]->[2.删除之前缓存数据。]
							->[3.插入新的数据。]

					</p>
				</div>
				<!--  end of 4.2.4  -->
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">通过Android服务建立缓存</h3>
					<p>
						主要流程为：
							[1.创建服务]->[2.根据菜单类别，从数据查询出数据。]->[3.存入以菜单的类别为key的HashMap中。]
					</p>
				</div>
				<!--  end of 4.2.5  -->
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">显示桌子功能</h3>
					<p>
						主要流程为：  [1.下载桌子数据]->[2.根据桌子数据，构建界面。] 
					</p>
				</div>
				<!--  end of 4.2.5  -->
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">显示菜品小类功能。</h3>
					<p>
						主要流程为：  [1.读取菜单小类信息。]->[2.构建菜单小类显示面板。] 
					</p>
				</div>
				<!--  end of 4.2.6  -->
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">显示菜品功能。</h3>
					<p>
						主要流程为：  [1.根据菜单小类读取菜品信息。]->[2.构建菜品显示。] 
					</p>
				</div>
				<!--  end of 4.2.7  -->
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">点菜功能。</h3>
					<p>
						主要流程为： 
							[1.读取菜品参数。]->[2.提交服务器。]->[3.如果提交成功，将菜品添加到已点菜单列表，并提示] 
					</p>
				</div>
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">搜索菜品功能。</h3>
					<p>
						主要流程为： 
							[1.弹出搜索对话框。]->[2.分析用户输入]->[3.搜索]->[4.显示结果] 
					</p>
				</div>
				<!--  end of 4.2.8  -->
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">修改数量价格功能。</h3>
					<p>
						主要流程为： 
							[1.读取菜品参数。]->[2.显示修改数量价格界面。]->[3.如果数据有变化，继续。]->[4.如果数量减少并且菜品已经送过厨房，继续，否则提交修改请求到服务器。提示请求结果。]
							->[5.询问减少数量原因。]->[6.提交减少数量原因，及修改数据。提示请求结果] 
					</p>
				</div>
				<!--  end of 4.2.9  -->
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">改码功能。</h3>
					<p>
						主要流程为： 
							[1.读取菜品参数。]->[2.显示改码界面。]->[3.如果有已经改码信息，组织显示。]->[4.如果改码信息改变，向服务器提交改码请求。]
							->[5.显示结果提示]
					</p>
				</div>
				<!--  end of 4.2.10  -->
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">送厨房功能。</h3>
					<p>
						主要流程为：
							[1.判断送厨房类型(部分送，全部送)，然后收集需要送厨房已点菜单参数，如果有数据要送，继续，否则提示]->[2.向服务器提交送厨房请求。。]->[3.提示结果信息。]
						
					</p>
				</div>
				<!--  end of 4.2.11  -->
				<div class="sub_sub_section">
					<h3 class="sub_sub_section_name">给账单功能。</h3>
					<p>
						主要流程为： 
							[1.读取给账单参数，如果可以给账单，继续，否则提示。]->[2.向服务器提交给账单请求。。]->[3.提示结果信息。] 
					</p>
				</div>
				<!--  end of 4.2.11  -->
			</div>
			<!--  end of 4.2  -->
			<div class="sub_section">
				<h3 class="sub_section_name">4.3&nbsp;功能实现</h3>
				<p>
				现代应用程序的设计基本都遵循MVC框架来设计。
				MVC模式（三层架构模式）（Model-View-Controller）是软件工程中的一种软件架构模式，把软件系统分为三个基本部分：模型（Model）、视图（View）和控制器（Controller）。
MVC模式最早由Trygve Reenskaug在1974年提出，是施乐帕罗奥多研究中心（Xerox PARC）在20世纪80年代为程序语言Smalltalk发明的一种软件设计模式。
MVC模式的目的是实现一种动态的程式设计，使后续对程序的修改和扩展简化，并且使程序某一部分的重复利用成为可能。
除此之外，此模式通过对复杂度的简化，使程序结构更加直观。软件系统通过对自身基本部份分离的同时也赋予了各个基本部分应有的功能。<sup>[19]</sup>
				</p>
				<ul>
					<li><strong>控制器(Controller)</strong>- 控制器起到不同层面间的组织作用，用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据模型上的改变。</li>
					<li><strong>视图(View)</strong> - 视图层能够实现数据有目的的显示（理论上，这不是必需的）。在视图中一般没有程序上的逻辑。
					为了实现视图上的刷新功能，视图需要访问它监视的数据模型（Model），因此应该事先在被它监视的数据那里注册。。</li>
					<li><strong>模型(Model)</strong> - 用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。</li>
				</ul>
				<p>
				本系统也是遵循MVC框架风格来对系统进行设计的。
				本文先将在下面三节中，深入分析了实现MVC框架中各个层中所需要的技术，然后在每一节的后面都详细说明了如何使用对应的技术实现相关的系统功能。
				</p>
		    </div>
			
		</section>

		<section>
			<h2 class="section_name">5&nbsp;&nbsp;MVC风格的应用框架:M-数据模型层</h2>
			<p>Android提供了几种持久化数据的选项.选择哪一种取决于你的需求,例如数据是应用私有的,还是可以通过其它应用(和用户)来访问,应用需要多大的空间.
			</p>
			<div class="sub_section" data-role="collapsible" data-theme="a">
				<h3 class="sub_section_name">5.1&nbsp;Shared
					Preferences(共享首选项)</h3>
				<p>
					<code>SharedPreferences</code>
					类,提供了一个允许你保存访问持久化键值对的基本数据类型的通用框架. 你可以使用
					<code>SharedPreferences</code>
					来保存任何的基本类型数据:布尔值,浮点型,整型,字符串.这些数据当应用被杀掉时还是存储在的. 可以使用下面两个方法来取得一个
					<code>SharedPreferences</code>
					对象:
				<ul>
					<li><code>getSharedPreferences():</code>你可以通过给第一个参数指定一个道选项文件名标识符,如果你的应用需要多个首选项文件.</li>
					<li><code>getPreferences():</code>如果你的Acitivity只需要一个首选项文件,那么可以使用这个方法,因为这是你活动唯一的首选项文件.</li>
				</ul>
				<p>
				<p>写入值:
				<ol>
					<li>调用<code>edit()</code>来取得一个<code>SharedPreferences.Editor</code></li>
					<li>使用方法如:<code>putBoolean()</code>,<code>putString()</code>等来添加值.
					</li>
					<li>使用<code>commit()</code>提交新的值.
					</li>
				</ol>
				</p>
				<p>
					读取值:使用
					<code>SharedPreferences</code>
					的方法如
					<code>getBoolean()</code>
					和
					<code>getString()</code>
				</p>
			<div class="practise">
			   		<div class="sub_sub_section">
						<h4 class="sub_sub_section_name">5.1.1&nbsp;使用SharedPreferences存储用户设置偏好</h4>
						<p>
						  在一个系统设置功能中，我们需要在用户选择之后，将用户的选择保存起来。
						  Android平台为系统设置功能，提供了一个方便的android.preference.PreferenceActivity类
						  来进行设置操作。为用户在使用各种App时，对于设置有一个统一的使用体验，也方面应用开发者开发应用设置界面。
						  及保存用户设置值。
						</p>
						<p>
						 Android提供了在View之后的Preference包的各种设置选项界面类。
						 同样支持使用XML文件声明界面。下面是一个设置界面文件preferences.xml文件，存放在res/xml目录下。
						 界面提供了一个列表让用户可以选择是否启用触摸声音效果：	</p>
<pre>
	&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" &gt;

    &lt;PreferenceCategory android:title="@string/title_operation_effect" &gt;
        &lt;CheckBoxPreference
            android:enabled="true"
            android:key="pref_use_sound_effect"
            android:summary="@string/summary_use_sound_effect"
            android:title="@string/title_use_sound_effect" /&gt;
    &lt;/PreferenceCategory&gt;
&lt;/PreferenceScreen&gt;
</pre>		
   <p>这个是用户设置界面，对应的Activity类如下：</p>	
   <pre>
public class DiPreferenceActivity extends PreferenceActivity {
private static final String TAG = "DiPreferenceActivity";

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	addPreferencesFromResource(R.xml.preferences);
	CheckBoxPreference mUseSound = 
	(CheckBoxPreference) findPreference("pref_use_sound_effect");
	mUseSound
	.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {

	@Override
	public boolean onPreferenceChange(Preference preference,
			Object newValue) {
		DiApplication.getInstance(getApplicationContext())
				.setUseClickSound((Boolean) newValue);
		DiSettings.putBoolean(getApplicationContext(),
				DiSettings.KEY_USE_SOUND_EFFECT,
				(Boolean) newValue);
		return true;
	}
	});
}
   </pre>
   <p>
   上面的代码中，当用户对设置进行了更改的时候，系统就会调用onPreferenceChange()方法，并将新的值传递给这个方法。
   然后，我的代码中，先是将用户设置保存在系统全局变量中，然后将其保存进用户偏好文件中。
   DiSettings.putBoolean()方法，正是使用SharePreference来保存用户的偏好的，代码如下： </p>
  <pre>
public static void putBoolean(Context context, String key, Boolean value) {
	SharedPreferences settings = PreferenceManager
			.getDefaultSharedPreferences(context);
	Editor editor = settings.edit();
	editor.putBoolean(key, value);
	editor.commit();
}
  </pre>
  
  <p>
   系统中使用偏好的地方还有，如保存服务器连接的ip及端口信息，保存最后更新的菜单数据时间，等等。
  </p>
				    </div>
			
			</div><!--  end of practice -->
				

			</div>
			<!--  end of 5.1 -->

			<div class="sub_section" data-role="collapsible" data-theme="a">
				<h3 class="sub_section_name">5.2&nbsp;使用外部存储空间</h3>
				<p>
					每一个Android兼容的设备都支持一个共享的"外部存储",可以用来存储文件.这可以是一个可热插拔的存储媒介(例如SD卡)或者是内部的存储空间(不可删除).
					保存在外部存储空间的文件是全局可读的.并且可以被用户修改,如,当用户将它们作为在容量的USB存储设备连接在电脑上时. <q><strong>注意:</strong>当用户将外部存储挂载在一个电脑上或者移除了这个介质时,文件将不可用.所以对于存储在外部存储空间的文件没有什么什么安全保证.应用可以读写存储在外部存储空间的文件,用户也可以删除它们.</q>
				<p>
				<div class="sub_sub_section">
					<h4 class="sub_sub_section_name">5.2.1&nbsp;检测外部媒介的可用性</h4>
					<p>
						在你对外部存储空间做任何操作之前,你应该调用
						<code>getExternalStorageState()</code>
						来检测介质是否可用. 介质也许正挂载在电脑上,或者没有,或者是只读的.或者在其它的状态中.示例:如何检测介质可用性:
					<pre>
boolean mExternalStorageAvailable = false;
boolean mExternalStorageWriteable = false;
String state = Environment.getExternalStorageState();

if (Environment.MEDIA_MOUNTED.equals(state)) {
    // 介质可读写
    mExternalStorageAvailable = mExternalStorageWriteable = true;
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
    // 介质只读 
    mExternalStorageAvailable = true;
    mExternalStorageWriteable = false;
} else {
    // 什么地方出错了,介质也许正处于其它状态.
    // 但是我们只需要知道是否可读或者可写. 
    mExternalStorageAvailable = mExternalStorageWriteable = false;
}
				  	 			</pre>
					上面的示例,检测外部存储介质是否是是可读写的.
					<code>getExternalStorageState()</code>
					可能返回其它的状态,你应该作出检查.如是否介质是共享的(指连接到了电脑上),或者根本没有外部存储,被移除了等等.如果你需要访问外部介质的话,你可以通知用户.
					</p>
				</div>
				<div class="sub_sub_section">
					<h4 class="sub_sub_section_name">5.2.2&nbsp;访问在外部存储中的文件</h4>
					<p>
						如果你正在使用API级别8或者更高的,使用
						<code>getExternalFilesDir()</code>
						来打开一个文件,它代表了你应该用来保存你文件的路径. 这个方法需要一个
						<code>type</code>
						参数.指定了你需要某种指定类型的子目录,例如
						<code>DIRECTORY_MUSIC</code>
						和
						<code>DIRECTORY_RINGTONES</code>
						(取得你应用的根目录你可以传递一个
						<code>null</code>
						值进去).
						如果必要的话,此方法将会创建相应目录.通过指定目录的类型,你可以确保Android系统媒体扫描程序将把你的文件在系统中归为合适的类别(例如,铃声被认为是铃声而不是音乐).如果用户卸载了你的应用,这个目录及并且它里面所有的内容都将被删除.
					</p>
					<p>
						如果,你正使用API级别7或者更低的.使用
						<code>getExternalStorageDirectory()</code>
						,来打开一个对应外部存储设备根目录的文件.然后你可以将你的数据写入下面的目录: <br />
						<code>/Android/data/&lt;package_name&gt;/files/</code>
						<br /> &lt;package_name&gt;是应用的Java风格的包名,例如"
						<code>com.example.android.app</code>
						".如果用户的设备正在运行级别8或者更高级别的API.他们卸载应用的时候,应用的目录及里面的内容将被删除.
					</p>

				</div>
				<div class="sub_sub_section">
					<h4 class="sub_sub_section_name">5.2.3&nbsp;保存需要共享的文件</h4>
					<p>
						如果需要保存一些并不是特定于应用,并且当应用被卸载时这些文件也不被删除,可以将他们保存在公共的外部存储目录里.这些目录都在外部存储空间的根目录中.例如
						<code>Music/</code>
						,
						<code>Pictures</code>
						,
						<code>Ringtones</code>
						,及其它.
					</p>
					<p>
						在级别8或者更高级别的API中,使用
						<code>getExternalStoragePublicDirectory()</code>
						,传递你需要的公共目录类型.例如
						<code>DIRECTORY_MUSIC</code>
						,
						<code>DIRECTORY_PICTURES</code>
						,
						<code>DIRECTORY_RINGTONES</code>
						等等.如果必要的话这些方法将创建合适的目录.
					</p>
					<p>
						如果使用级别为7或者级别更低的API的话,使用
						<code>getExternalStorageDirectory()</code>
						来打开代表着外部存储空间根目录的的
						<code>File</code>
						, 然后你可以将你的共享文件保存在下面这些目录中:
					<ul>
						<li><code>Music/</code>-媒体扫描器将此目录下的媒体归类为音乐.</li>
						<li><code>Podcats/</code>-媒体扫描器将此目录下的媒体归类为podcast.</li>
						<li><code>Ringtones/</code>-媒体扫描器将此目录下的媒体归类为铃声.</li>
						<li><code>Alarms/</code>-媒体扫描器将此目录下的媒体归类为警铃.</li>
						<li><code>Notifications/</code>-媒体扫描器将此目录下的媒体归类为提示声.</li>
						<li><code>Pictures/</code>-所有的图像(不包含那些使用照像机拍摄的).</li>
						<li><code>Movies/</code>-所有的电影(不包括那些用摄像机拍摄的.).</li>
						<li><code>Download/</code>-下载杂项.</li>
					</ul>
					</p>
				</div>
				<!--  end of saving files that should be shared -->
				
	<div class="practice">
	   <div class="sub_sub_section">
			<h4 class="sub_sub_section_name">5.2.4&nbsp;外部存储空间及应用更新功能实现</h4>
			<p>
			其实这个自动更新功能大体就是两个三个步骤:(1)检查更新,(2)下载更新,(3)安装更新。
			检测更新与下载更新，都是向服务器发送请求，然后下载数据，执行操作。
			实现的主要关键点是安装更新。首先使用上面提到的知识点，将需要更新的应用的APK文件下载放到如Downloads中，
			然后，安装就主要使用Android平台系统提供的查看此文件的功能，然后系统检测到此文件是一个APK文件，因此会提示用户是否
			安装，然后，如果用户选择是的话，则就会安装新应用。
			安装使用使用下面的方法，方法参数是上面提到下载保存在相应目录中的文件的绝对路径：
			</p>
			<pre>
private void installApk(String fileUri) {
	Intent intent = new Intent(Intent.ACTION_VIEW);
	intent.setDataAndType(Uri.parse("file://" + fileUri),
			"application/vnd.android.package-archive");
	startActivity(intent);
	this.finish();
}
			</pre>
		</div>	
	
	</div>


			</div>
			<!--  end of 5.2  -->
			<div class="sub_sub_section" data-role="collapsible" data-theme="a">
				<h3 class="sub_section_name">5.3&nbsp;使用数据库</h3>
				<p>Android提供了对SQLite数据库的完全支持.你所创建的数据库都可以通过名字来访问,但是在其它应用中却不能.</p>
				<div class="sub_sub_section">
					<h4 class="sub_sub_section_name">5.3.1&nbsp;基本用法</h4>

					<p>
						创建一个新的SQLite数据库的推荐方法是创建一个
						<code>SQLiteOpenHelper</code>
						的子类.并且重写
						<code>onCreate()</code>
						方法, 可以在此方法中执行一些SQLite命令来在数据库中创建表.示例如下:
					<pre>
public class DictionaryOpenHelper extends SQLiteOpenHelper {

    private static final int DATABASE_VERSION = 2;
    private static final String DICTIONARY_TABLE_NAME = "dictionary";
    private static final String DICTIONARY_TABLE_CREATE =
                "CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" +
                KEY_WORD + " TEXT, " +
                KEY_DEFINITION + " TEXT);";

    DictionaryOpenHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(DICTIONARY_TABLE_CREATE);
    }
}
				  	 	</pre>
					可以通过你定义的构造方法来获得你的实现的
					<code>SQliteOpenHelper</code>
					实例.读取和写入数据库,调用
					<code>getWritableDatabase()</code>
					和
					<code>getReadableDatabase()</code>
					,一般来说,他们都返回
					<code>SQliteDatabase</code>
					对象,它代表了数据库,并提供了用于SQlite操作的方法.
					<p>
					<p>
						可以使用
						<code>SQliteDatabasequery()</code>
						方法来执行SQLite查询,这个方法接收各种查询参数,例如,要查询的表,映射,选择,列,分组,及其它.
						对于复杂的查询,例如需要对列重命名,则应该使用
						<code>SQliteQueryBuiler</code>
						,它接收多个方便的方法用于构造查询.
					</p>
					<p>
						每一个SQlite查询都将返回一个
						<code>Cursor</code>
						指向查询出来所有行.
						<code>Cursor</code>
						是你用来在数据结果中导航读取数据行及列的机制.
					</p>
				</div>
				<div class="sub_sub_section">
					<h4 class="sub_sub_section_name">5.3.2&nbsp;使用SQLite数据库保存菜单数据，及浏览菜品实现</h4>
					<p>
					SQlite支持基本完整的SQL实现。可以方便的实现菜品数据持久保存在SQlite本地数据为中。
					基本的数据层中，我首先对数据进行建模，即以一个实体类的表示数据中表对应的数据集。
					然后在数据库操作层处理将对象分析保存到数据中，及将数据从数据库查询出来，保存在实体类列表中的。
					菜品中实体类为Menux对应的数据库表模型，可以通过创建表的SQL语句表述如下：</p>
<pre>
create table  menux (
 id integer primary key autoincrement, 
 menutype varchar, /*菜品大类名 */
 groupx varchar, /*菜品小类名 */
 boxeng varchar, /*菜品第一语言表述 */
 boxchn varchar, /*菜品第二语言表述 */
 boxid varchar, /*菜品在菜品格子中的标识 */
 menuguid varchar, /*菜品唯一标识符 */
 price varchar ); /*菜品价格 */
</pre>
					<p>下面的代码将一系统菜品列表保存到数据为中：</p>
					
<pre>
public void addMenuxs(List&lt;Menux&gt; menuxs) {
	String sql = "insert into menux(menutype, groupx,boxeng ,boxchn ,boxid ,menuguid ,price )"
	             +" values(?,?,?,?,?,?,?) ;";
	SQLiteDatabase wDb = getWritableDatabase();
	wDb.beginTransaction();
	try {
		SQLiteStatement ps = wDb.compileStatement(sql);
		for (Menux menux : menuxs) {
			ps.bindString(1, menux.getMenutype());
			ps.bindString(2, menux.getGroupx());
			ps.bindString(3, menux.getBoxeng());
			ps.bindString(4, menux.getBoxchn());
			ps.bindString(5, menux.getBoxid());
			ps.bindString(6, menux.getMenuguid());
			ps.bindString(7, menux.getPrice());
			ps.executeInsert();
		}
		wDb.setTransactionSuccessful();
	} finally {
		wDb.endTransaction();
	}
}
</pre>
<p>
从数据库将数据读取出来，再将数据转换成实体类的过程稍微复杂一些，查询出所需要的数据记录之后，首先通过对应字段在数据表的名字，然后，查找到字段的索引，再通过索引查询出值。出来。
下面是从数据库通过给定的menutype及groupx查出符合条件的菜品记录，并读取menutype属性值的过程代码。
</p>
<pre>
Cursor cursor = getReadableDatabase().rawQuery(FIND_BY_MENUTYPE_GROUPX,
		new String[] { menutype, groupx });
// 读取所在列索引值
int menutypeIndex = cursor.getColumnIndex("menutype");
// 读取对应值
String menutype = cursor.getString(menutypeIndex);
</pre>
				</div>

			</div>
			<!--  end of 5.3  using Database -->		

		</section>
		<!--  end of  5  -->


		<section>
			<h2 class="section_name">
				6&nbsp;&nbsp;MVC风格的应用框架:V-视图界面打造现代自然的用户界面</h2>
			<p>android系统，并没有使用Java桌面的Swing，及AWT等重量级UI系统。android使用的是基于XML形式声明式为主（也还可以使用Swing形式的命令式UI技术）UI技术。
				同时Android提供了良好的资源组织访问方式。 同时android提供了各种机制来支持创建支持各种设备自然丰富良好的用户体验。</p>
			<div class="sub_sub_section">
				<h3 class="sub_sub_section_name">6.1&nbsp;Android应用程序资源</h3>
				<p>Android将应用的资源独立出来。对于任何类型的资源都可以有一个默认值和多个可选的值。以增加各种对各种设备的兼容性。
					例如android中应用默认的UI布局文件放在res/layout目录下。而当你想为横向界面指定UI文件时，则放在res/layout-land／目录下，android会根据系统设备当前的配置，自动匹配资源目录。
				</p>
				<div class="sub_sub_section" data-role="collapsible" data-theme="a">
					<h4 class="sub_sub_section_name">6.1.1&nbsp;资源类型(Resource
						Types)</h4>
					<p>android中每一种资源都统一放在res/目录下.其中包括发以下几种主要的资源类型:
					<dl>
						<df>布局资源(Layout Resource)</df>
						<dd>
							定义应用的布局的UI.<br />放在/res/layout目录下,使用R.layout类访问.
						</dd>
						<df>图像资源(Drawable Resources)</df>
						<dd>
							使位图或者xml定义各种图形.<br />保存在res/drawable/目录下,通过R.drawable类访问.
						</dd>
						<df>动画资源(Animation Resources)</df>
						<dd>
							定义动画资源.</br>补间动画(Tween animations)保存在res/anim目录下,通过R.anim类访问.<br />帧动画(Frame
							animations)保存在res/drawable/目录里,通过R.drawable类访问.
						</dd>
						<df>颜色状态列表资源(Color State List Resource)</df>
						<dd>
							定义了基于View状态改变的颜色资源.<br />保存在res/color目录下,通过R.color类访问.
						</dd>
						<df>菜单资源(Menu Resource)</df>
						<dd>
							定义应用程序的菜单<br />保存在res/menu目录下,通过R.menu类访问.
						</dd>
						<df>字符串资源(String Resource)</df>
						<dd>
							定义字符串,字符数组,及复数资源(同时包括字符串格式化及样式.)<br />保存在res/values/目录下,通过R.string类,或者R.array类,及R.plurals类访问.
						</dd>
						<df>样式资源(Style Resource)</df>
						<dd>
							定义UI元素的外观及格式.<br />保存在res/values目录下.通过R.style类访问.
						</dd>
						<df>其它资源</df>
						<dd>
							其它的值资源如,布尔值,整形值,尺寸,颜色,或者其它数组.<br />保存在res/values目录下,都是通过R的唯一子类(例如R.bool,R.integer,R.dimen,等等)来访问.
						</dd>
					</dl>
					<p>
				</div>
				<!--  end of 6.1.1  -->

				<div class="sub_sub_section" data-role="collapsible" data-theme="a">
					<h4 class="sub_sub_section_name">6.1.2&nbsp;访问资源</h4>
					<p>
						Android工具,aapt会自动为应用资源产生一个名为R的类文件.里面定义了所有资源的ID.你可以通过资源ID来引用资源.
					<p>
					<p>程序编译时,aapt会自动编译生成R类文件,包含了res/目录下所以资源的资源ID.对于所有类型的资源,都有一个对应的R子类(例如R.drawable对应所有的图像文件).对于某种类型的资源,都有一个静态的整形(例如,R.drawable.icon),这个整形值就是你用来取得你资源的资源ID.</p>
					<p>虽然,在R类中声明了资源ID,但我们并不需要查看这个类来查询资源ID.一个资源ID由以下两个部分组成:
					<ul>
						<li><strong>资源类型:</strong>每一个资源都属于某种类型,例如,字符串(string),图像(drawable),布局(layout).</li>
						<li><strong>资源名:</strong>对于在XML文件中定义的简单的值(如字符串),名字是定义在android:name属性中的值；其它类型的资源,资源名则是不包括扩展名的文件名.</li>
					</ul>
					</p>
					<p>有以下两种方式来访问资源:
					<ul>
						<li><strong>在代码中:</strong>使用R类资源类型对应子类的静态整型来访问如:<code>R.string.hello</code>,<code>string</code>是资源类型.<code>hello</code>是资源名.Android提供了很多API来让我们通过这种格式的资源ID来访问资源.</li>
						<li><strong>在XML中:</strong>使用一个特别的XML语法来对应定义在R类中的资源ID如<code>@string/hello</code>,<code>string</code>是资源类型,<code>hello</code>是资源名.可以在XML文件中使用这种方法来取得你应用中任意资源.</li>
					</ul>
					</p>


				</div>
				<!--  end of 6.1.2 -->
			</div>
			<!--  end of 6.1 -->

			<div class="sub_section">
				<h3 class="sub_section_name">6.2&nbsp;Android&nbsp;UI系统</h3>
				<p>
					在一个Android应用中，用户界面使用
					<code>View</code>
					和
					<code>ViewGroup</code>
					对象。有多种不同类型的Views和ViewGroup，每一个都是
					<code>View</code>
					类的 子类。
				</p>
				<p>
					View对象是在Android平台中用户界面表现中最基本单元。View类用于基础表现的子类称之为"Widgets"，它提供了完整的UI系统实现，
					例如文本字段，按钮。ViewGroup是称为"layouts"的子类的基础，它提供了各种不同类型的布局结构，例如线性，标签式，及相对的等等。
				</p>
				<p>
					一个View对象，是一个存储布局参数及指定屏幕矩形区域内容的数据结构。一个View对象，负责它自己的拥有的矩形交互区域的测量，布局，绘制，焦点处理，滚动，
					按键/手势交互。对于用户界面的一个对象，一个View是一个以接收交互事件及与用户交互的交互点。</p>

				<div class="sub_sub_section">
					<h4 class="sub_sub_section_name">6.2.1&nbsp;View的层级结构</h4>
					<p>
						在Android平台，可以通过定义一个View和ViewGroup节点的层级结构来定义一个Activity的UI，如右图所示。
						这个层级树可以是简单的也可以是复杂的，由开发者决定，可以使用Android预定义的一些Widgets及Layouts集合，或者自定义的Views来构建界面。
													<div class="img_wrapper">
				<img src="drawables/viewgroup.png" title="viewgroup" />
					<p class="pic_desc">图&nbsp;6.1&nbsp;AndroidUI布局View层级关系示意图</p>
					</div>
						
					</p>
					<p>
						为了将View的层级树跟屏幕的渲染联结起来，应用的Activity必需调用
						<code>setContentView()</code>
						方法并将层级树的根节点引用传递进去。
						Android系统接收这个引用，并用它来重绘，测量，绘制层级树。层级的根节点请求它的子节点绘制它们自己。反过来，每一个viewgroup节点
						则需要调用它自己的子View绘制它们自己。子View向父节点请求一个大小及位置，但是父节点对象有最终的决定权来决定每一个子view有多大。
						Android系统从上到下按顺序解析层级树，实例化View对象，将其添加到他们的父节点中。因为他们是按顺序绘制的，如果有无线越界了，
						那么最后的view将绘制在它前面的View空间上面。
					</p>
				</div>
				<!--  end of 6.2.1 -->

				<div class="sub_sub_section">
					<h4 class="sub_sub_section_name">6.2.2&nbsp;Android绘制View的方式</h4>
					<p>
						当一个Activity接收到焦点的时候，它将绘制它的布局(layout)。Android框架会处理绘制过程，但是Activity必须提供它的层级布局的根节点。
					</p>
					<p>
						绘制从布局的根节点开始，根节点将测量及绘制整个布局树。绘制过程是遍历整个层级树渲染每一个View中有有效区域的部分。反过来，每一个
						viewgroup都负责请求每一个子View来绘制(通过调用
						<code>draw()</code>
						)，然后每一个View对自己负责。因为对于层级树的遍历
						是有顺序的，这意味着父View会在子View之前绘制，它的兄弟节点将根据在层级树中出现的顺序依次绘制。
					</p>
					<p>
						绘制布局(layout)经过两个过程：一个是测量一个是布局。测量步骤在
						<code>measure(int,int)</code>
						中实现，并且并且是对view层级树至顶向个的遍历。
						每一个view在递归遍历中将尺寸声明向下传递。在测量过程之后，每一个View都存储了自己的尺寸测量信息。 第二个步骤是在
						<code>layout(int,int,int,int)</code>
						中进行，同样是至顶向下的。在这一过程中，每一个父节点负责使用在测量过程中计算出的尺寸信息来放置它所有的 子节点。<br /> <q>
							Android框架不会绘制不在有效区域的View。但是还是会好好的在后台处理好这些View。如果需要强制绘制这些View，可以调用
							<code>invalidate()</code>来实现。
						</q>
					</p>
					<p>
						当一个View的
						<code>measure()</code>
						方法返回了，它的以及它的后代View。
						<code>getMeasureWidth()</code>
						和
						<code>getMeasureHeight()</code>
						值必须设置。一个View的测量宽度及高度必须考虑父View的会提供限制。这可以保证在测量过程的最后，父View都会接收所有子View的测量值。一个父View对子View调用
						<code>measure()</code>
						不只一次，例如当父View使用不同的声明尺寸来找出子View需要多大的尺寸，如果所以子View未限制的尺寸太大了或者太小了，父View将用实现的数值重新在子View中调用
						<code>measure()</code>
						(也就是说，如果子View自己对他们可以得到尺寸空间不满意，父View将干预并在第轮中设置规则。)
					</p>
					<p>
						测量过程使用两个类来交流尺寸。
						<code>View.MeasureSpec</code>
						被View用于告诉父View他们想要多大的尺寸及怎么放置。 基本的
						<code>LayoutParams</code>
						类，描述了View在宽度及高度上想要多大。每对于一个尺寸，可以由下面的数值指定：
					<ul>
						<li>一个具体的值</li>
						<li><code>FILL_PARENT(MATCH_PARENT)</code>，意味着View想要跟父View一样大（最小的内边距），在android
							api 8开始使用<code>MATCH_PARENT</code>这一常量，因为更符合语义。</li>
						<li><code>WRAP_CONTENT</code>，意味着这个View只要包围内容的大小(加内边距)</li>
					</ul>
					ViewGroup的不同子类有不同的
					<code>LayoutParams</code>
					子类，例如
					<code>RelativeLayout</code>
					有它自己的
					<code>LayoutParams</code>
					子类， 它包括了将子View水平及垂直居中的能力。
					</p>
					<p>
						<code>MeasureSpecs</code>
						用于从父View向子View传递测量需求。一个
						<code>MeasureSpec</code>
						包含下面三个模式:
					<ul>
						<li><code>UNSPECIFIED:</code>这个被父View用于决定子View想要的尺寸。例如一个<code>LinearLayout</code>
							也许会调用<code>measure()</code>，并将height指定为<code>UNSPECIFIED</code>并且宽度为一个<code>EXACTLY</code>
							240值，来判断子View在给定240像素宽时需要多高。</li>
						<li><code>EXACTLY：</code>用于父View给子View一个指定的尺寸。子View必须使用这个尺寸值。并且保证它所以的后代子View填充这个尺寸。</li>
						<li><code>AL_MOST：</code>，用于父View给子View传递一个最大的尺寸值。子View必须保证它和它所以的后代将填充这个尺寸。</li>
					</ul>
					</p>
				</div>
			</div>
			<!-- end of 6.2 -->

			<div class="sub_ssection">
				<h3 class="sub_section_name">6.3&nbsp;Android UI部件及事件</h3>
				<p>Android框架中提供了丰富完全的布局，Widgets，事件处理，菜单等UI部件。</p>

				<div class="sub_sub_section">
					<h4 class="sub_sub_section_name">6.3.1&nbsp;布局</h4>
					<p>定义布局最常用的方式就是使用一个XML布局文件来声明View层级。
						XML提供了一个容易查阅布局结构，有点像HTML。在XML文件中每一个元素一般要么是一个View或者是一个ViewGroup（或者它的后代），View对象在层级树中是叶节点，
						ViewGroup对象在层级树中是分支节点。（参见上面的层级图）</p>
					<p>
						XML元素名对应它所代表Java类的名称。因此一个
						<code>&lt;TextView&gt;</code>
						是一个你的UI中的一个
						<code>TextView</code>
						，一个
						<code>&lt;LinearLayout&gt;</code>
						元素创建一个
						<code>LinearLayout</code>
						view group。当加载一个布局资源时，Android系统将实例化这些运行时对象，对应于你的布局中的元素。
					</p>
					<p>下面是一个简单的带有一个 text view和一个按钮的垂直布局：</p>

					<pre>
&lt;?xml version="1.0" encoding="utf-8"?>
&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent" 
              android:layout_height="fill_parent"
              android:orientation="vertical" >
    &lt;TextView android:id="@+id/text"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="Hello, I am a TextView" />
    &lt;Button android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button" />
&lt;/LinearLayout>
							</pre>
							<p>
							Android系统框架中提供的基本布局有LinearLayout,RelativeLayout,TableLayout,GridLayout(api 14之后才可用)，使用Gridlayout_v7这一android支持包
							可以在api 7之后的版本使用GridLayout。
							</p>

				</div>
				<!--  end of 6.3.1 -->

				<div class="sub_sub_section">
					<h4 class="sub_sub_section_name">6.3.2&nbsp;Widgets</h4>
					<p>
						一个Widget是一个用户交互界面。Android系统提供了丰富的完整的Widgetg集，如按钮，单选按钮，文本输入框，可以用来方便快速的
						构建用户界面。Android也提供了一些复杂的Widgets如，日期选择器，时钟，缩放控件。开发者可以不必限于Android平台提供的UI组件，
						可以自定义创建自己的UI控件元素，例如，可以定义自己的View对象，或者扩展，组合已有的Widgets。android平台提供的widgets在
						<code>android.widget</code>
						包中。

					</p>
				</div>
				<!--  end of 6.3.2 -->

				<div class="sub_sub_section">
					<h4 class="sub_sub_section_name">6.3.3&nbsp;事件</h4>
					<p>向UI添加一些Views/Widgets之后，也许需要知道用户与之进行交互，并执行某些操作。
						要了解事件，需要做下面两件事件中的一件：</p>
					<ul>
						<li><strong>给View注册一个定义的事件监听器。</strong>，没有更多了，这样就可以监听事件了。
							View类包含了一系列名为On;&lt;<i>something</i>&gt;Listener 的嵌套接口，每一个都有一个叫做<code>
								On&lt;<i>something</i>&gt;()
							</code>的回调方法。 。例如，<code>View.OnClickListener()</code>（用于处理在View上的点击(click)），<code>View.OnTouchListener</code>
							(用于处理在一个View上的屏幕触摸事件)，<code>View.OnKeyListener</code>（用于处理在一个View上的按键事件）。
							因此如果需要某一个在“点击”（如选择了某一个按钮）的时候得到通知，实现OnClickListener并且定义它的<code>onClick</code>回调方法
							（点击动作后，在这个方法中执行某操作），并调用<code>setOnClickListener()</code>将它注册到View中。

						</li>
						<li><strong>重写View中已经存在的回调方法。</strong>当实现自定义的View类时，如果需要监听在其中发生的某种事件。能够处理的示例事件有，当触摸屏幕时(<code>onTouchEvent</code>)</li>
						，当滚动轮滚动的时候(
						<code>onTrackballEvent()</code>
						)，或者当设置的一个按键被按下时(
						<code>onKeyDown()</code>
						)。这将允许你定义在自定义View中的默认行为，并且决定事件是否应该传递到
						一些其它的子View中。同样这有一些View类的回调函数，因此唯一定义他们的机会就是在你创建自定义组件的时候。
						</li>
					</ul>
					<p>
						<strong>Android事件触发顺序</strong><br/>
						对于应用来说，首先接收到事件的是Activity类的Activity:dispatchTouchEvent()，然后，
						是事件发生的所有布局的所属直接父View的onInterceptTouchEvent()。如果此方法返回true，则其子View将不再接收到事件，而是此View本身的接收处理此事件。
						然后是，上面讨论到的view类的onTouchEvent()方法。如果此方法返回false，那么事件最后将传递到Activity的onTouchEvent()方法中。
					</p>
				</div>
				<!--  end of 6.3.3  -->

				<div class="sub_sub_section">
					<h4 class="sub_sub_section_name">6.3.4&nbsp;菜单</h4>
					<p>
						应用的菜单是应用UI的另一个重要的组成部分。菜单是一个可靠的展示用户功能及设置的界面。最常用的展示应用菜单的方式是按下设置上的<i>Menu</i>
						按键。但是也可以添加上下文菜单，如当用户长按某一项时展开。
					</p>
					<p>
						菜单同样使用View层级的组织结构，但是并不需要开发者自定义这个结构，相反，你可以在你的Activity中定义
						<code>onCreateOptionsMenu()</code>
						或者
						<code>onCreateContextMenu()</code>
						回调方法，并且声明需要包含在菜单中的项。在合适的时间，Android将自动为菜单创建必要的层级，并将你的菜单项绘制在上面。
					</p>

					<p>
						菜单同样会处理它们自己的事件，因此没有再为菜单中的菜单项注册事件监听器了。当菜单中的某一项选中时，
						<code>onOptionsItemSelected()</code>
						，和
						<code>onContextItemSelected()</code>
						方法 将被框架调用。
					</p>
					<p>正如应用的布局一样，也可以将菜单项声明在一个XML文件中。</p>
				</div>
				<!--  end of 6.3.4 -->

				<div class="sub_sub_section">
					<h4 class="sub_sub_section_name">6.3.5&nbsp;适配器（Adapter)</h4>
					<p>
						有些时候需要像view group填充一些不能硬编码的信息，而是需要绑定View到一个外部的数据源。
						为了达到这个目的，需要使用一个AdapterView的view
						group，它当中的每一个子View都是用Adapter中的数据来填充。
						<code>Gallery</code>
						，
						<code>ListView</code>
						，和
						<code>Spinner</code>
						都是AdapterView子类的例子。
					</p>
					<p>
						AdapterView是一个ViewGroup的子类，通过一个给定的Adapter对象来决定它的子View。Adapter扮演了一个在数据（可以是一个外部的字符串数组）与AdapterView之间的邮差，AdapterView用来显示它。
						有几种不同的Adapter类实现，对于指定的任务，例如CursorAdapter，用来从一个Cursor中读取数据库数据，或者一个ArrayAdapter用来从一个手写数组中读取数据。

					</p>
					<p>AdapterView主要负责两项任务：</p>
					<ul>
						<li>用数据填充布局</li>
						<li>处理用户的选择</li>
					</ul>
					<div data-role="collapsible" data-theme="a">
						<h5>用数据填充布局</h5>
						<p>将数据插入到布局中通常是通过将AdapterView类绑定到一个Adapter。
						<p>
						<p>下面的代码代码示例，做了以下事情：</p>
						<ol>
							<li>从一个已有的View中创建一个<code>Spinner</code>并将它绑定到一个新的ArrayAdapter中，并从本地数据中读取一个颜色数组。
							</li>
							<li>创建另一个Spinner对象，并将它绑定到一个新的SimpleCursorAdapter中，它将从设备的联系人中读取人名。</li>
						</ol>
						<pre>
// 取得一个Spinner并将它绑定到一个ArrayAdapter中，
//此ArrayAdapter有一个对字符串数组的引用。
Spinner s1 = (Spinner) findViewById(R.id.spinner1);
ArrayAdapter adapter = ArrayAdapter.createFromResource(
    this, R.array.colors, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s1.setAdapter(adapter);

// 加载一个Spinner，并将它绑定到一个查询语句。
private static String[] PROJECTION = new String[] {
        People._ID, People.NAME
    };

Spinner s2 = (Spinner) findViewById(R.id.spinner2);
Cursor cur = managedQuery(People.CONTENT_URI, PROJECTION, null, null);
     
SimpleCursorAdapter adapter2 = new SimpleCursorAdapter(this,
    android.R.layout.simple_spinner_item, // 使用显示文本的模板
    cur, // 使用到一个list adapter中的cursor
    new String[] {People.NAME}, // 映射数据库的人名到XML模板中的"text1"。
                                        
    new int[] {android.R.id.text1});
                                         
adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s2.setAdapter(adapter2);
				  	 		</pre>
						值得注意的是，在使用CursorAdapter时，在映射中必须要有People._ID，否则会有异常。
						<p>
							如果在你的应用的运行的某个阶段，你改变了Adapter读取的数据，应当调用
							<code>notifyDataSetChanged()</code>
							， 它将通知关联的View数据已经发生的变化，应该重绘了。
						</p>
					</div>
					<!--  end of filling the layout with Data  -->

					<div data-role="collapsible" data-theme="a">
						<h5>处理用户选择</h5>
						<p>
							可以通过设置类的
							<code>AdapterView.OnItemClickListener()</code>
							成员到一个监听器，并且捕获选择的变化。
						<p>
						<pre>
// 创建一个消息处理对象匿名内部类
private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() {
    public void onItemClick(AdapterView parent, View v, int position, long id)
    {
        // 显示一个消息盒子
        Toast.makeText(mContext,"You've got an event",Toast.LENGTH_SHORT).show();
    }
};

// 关联我们的对象及onClickItemListener成员到处理类。
// to our class handler object.
mHistoryView = (ListView)findViewById(R.id.history);
mHistoryView.setOnItemClickListener(mMessageClickedHandler); 
				  	 	</pre>
					</div>
					<!--  end of Handling User Selections -->

				</div>
				<!--  end of 6.3.5 -->

			</div>
			<!--  end of 6.3 -->
			<div class="practice">
		<div class="sub_sub_section">
			<h4 class="sub_sub_section_name">6.4&nbsp;使用GridView及自定义Adapter实现菜品格子显示</h4>
			<p>
			GridView是Android内置提供了一个以网络显示数据的Widget。
			首先是编写在XML布局文件中声明GridView如下：
			</p>
<pre>
 &lt;GridView
     android:id="@+id/menu_box"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_alignParentBottom="true"
     android:layout_marginTop="130dp"
     android:background="#081f41"
     android:clipChildren="true"
     android:drawSelectorOnTop="true"
     android:fastScrollEnabled="true"
     android:horizontalSpacing="5dp"
     android:numColumns="3"
     android:stretchMode="columnWidth"
     android:textFilterEnabled="true"
     android:verticalSpacing="5dp" /&gt;
</pre>
<p>
接着编写菜品项布局的XML文件。名为menu_item.xml。见附录三。<br/>
 然后继承BaseAdapter编写自定义的适配器。具体代码见附录四。
</p>
   
		</div>			
			</div>

		</section>
		<!--  end of 6 -->

		<section>
			<h2 class="section_name">7&nbsp;&nbsp;MVC风格的应用框架:C-应用控制器</h2>

			<div class="sub_section">
				<h3 class="sub_section_name">
					7.1&nbsp;Activity:控制器中心<sup>[8]</sup></sup>
				</h3>
				<div class="sub_sub_section ui-body ui-body-a">
					<h4 class="sub_sub_section_name">7.1.1&nbsp;创建Activity</h4>
					<p>Activity中文可以理解为活动。创建Activity继承android.app.Activity
						并重写onCreate()回调方法。重要的是在其中调用setContentView()来设置活动的用户布局界面。
						setContentView()可以接受一个布局的资源ID,或者一个根ViewGroup对象。</p>
					<div data-role="collapsible" data-theme="a">
						<h5>实现用户界面</h5>
						<p>一个活动的用户界面由层级视图提供，每一个视图控制一个能与用户交互的特殊的矩形显示区域。
							android提供了大量可重用的"widget"，和一些用来 组织这些小部件显示的"Layout"。
							通过xml的layout文件来实现用户界面是最常用的一种方式。</p>
					</div>
					<div data-role="collapsible" data-theme="a">
						<h5>在清单文件中声明activity</h5>
						<div>
							一个activity元素是一个application的子元素。
							<pre>
&lt;manifest ... &gt;
  &lt;application ... &gt;
      &lt;activity android:name=".ExampleActivity" /&gt;
      ...
  &lt;/application ... &gt;
  ...
&lt;/manifest &gt;
									</pre>
							
						</div>
					</div>

					<div data-role="collapsible" data-theme="a">
						<h5>使用意图过滤器</h5>
						<div>
							一个activity元素能够指定多种意图过滤器，使用intentj-filter元素。 一个主activity包含的过滤器示例：
							<pre>
&lt;activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"&gt;
    &lt;intent-filter&gt;
        &lt;action android:name="android.intent.action.MAIN" /&gt;
        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
    &lt;/intent-filter&gt;
&lt;/activity&gt;
									</pre>
							action元素指明这是这个应用的主入口。category元素声明这个活动应该列在系统应用程序的启动器上，允许用户启动这个活动。
							为了让其它应用程序通过隐式意图来使用你的活动，你必需为你的活动使用intent-filter元素来说明，action子元素是必要的，category和data元素是可选的。
						</div>
					</div>
				</div>
				<!-- end of 7.1.1 /themed container -->

				<div class=" sub_sub_section ui-body ui-body-a">
					<h4 class="sub_sub_section_name">7.1.2&nbsp;启动Activity</h4>

					<div data-role="collapsible" data-theme="a">
						<h5>启动自己应用的活动</h5>
						<p>可以向startActivity(Intent intent)传递一个Intent来启动活动。
							在在自己的应用中，你只是要启动一个已经的活动。这样可以像下面这样简单：
						<pre>
Intent intent = new Intent (this,SignInActivity.class);
startActivity(intent);
				  				</pre>
						</p>
					</div>

					<div data-role="collapsible" data-theme="a">
						<h5>通过某种意图启动活动。</h5>
						<p>如果你想要让用户发送电子邮件，你可以创建如下意图：
						<pre>
Intent intent = new Intent (Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL,recipientArray);
startActivity(intent);
				  		    	</pre>
						</p>
					</div>

					<div data-role="collapsible" data-theme="a">
						<h5>为得到结果启动一个活动</h5>
						<p>从启动某种活动得到结果。使用startActivityForResult()方法。
							然后实现onActivityResult()回调方法，当子活动完成之后，会将带返回结果的Intent
							传递给onActivityResult()方法。 例如，想让用户选择一个联系人。下面是示例代码：
						<p>
						<pre>
 private void pickContact(){
   Intent intent = new Intent(Intent.ACTION_PICK,Contacts.CONTENT_URI);
   startActivityForResult(intent,PICK_CONTACT_REQUEST);
 }
 
 @Override
 protected void onActivityResult(int requestCode,int resultCode,
                                    Intent data){
	if(resultCode == Activity.RESULT_OK && 
	       requestCode == PICK_CONTACT_REQUEST){
	// 从 联系人的content provider中查询联系人的名字。
	Cursor cursor = getContentResolver().query(data.getData(),
	         new String[]{Contacts.DISPLAY_NAME,null,null,null});
	if(cursor.moveToFirst()){ // True 如果Cursor不为空
		int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
		String name = cursor.getString(columnIndex);
		// 使用联系人信息，执行某些操作。
		
		}
	}
 }
				  			</pre>

					</div>


				</div>
				<!-- /themed container  end of 7.1.2-->

				<div class="sub_sub_section ui-body ui-body-a">
					<h4 class="sub_sub_section ">7.1.3&nbsp;Android多任务机制</h4>
					<p>所以的activity属于某一个任务。一个任务包含与用户交互的activity集合。任务能够在后台保留用户的交互状态。当用户在activity中切换时。
						某一个活动也许是其它应用程序的。如通过隐式意图启动的某些活动。
						通过在主屏幕打开一个应用。此应用的主Activity打开作为在任务栈中的根activity.
						在此当前的activity打开另一个时，新的Activity被压入任务栈的顶部并获得用户焦点。而前一个
						activity依然在任务栈中。当用户按下后退键时，当前的Actity从任务栈中弹出（销毁),前面的活动
						将恢复。在任务栈中的活动不会重排。只是压入和弹出。
						当所以的activity都从任务栈中公移出时，任务将不存在。一个任务是一个紧密联系的单元。</p>
					<div data-role="collapsible" data-theme="a">
						<h5>保护活动状态(Saving Activity State)</h5>
						<p>虽然系统会恢复任务栈中活动的状态，但在内存不足时任务栈中的状态将不会保留。
							为了避免状态丢失。可以在回调函数中主动保存状态，即重写onSaveInstanceState()方法。</p>
					</div>
					<div data-role="collapsible" data-theme="a">
						<h5>定义启动模式(Defining launch modes)</h5>
						<div>启动模式允许你定义一个活动的新的实例如何与当前的任务想关联。
							你通过在清单文件中配置，或者使用Intent标志。 如果有活动A，活动B，如果活动B在清单文件中定义了此活动将如何与任务关联，
							而活动A在启动活动B的时候也定义了活动B将如何与任务相关联。那么活动A在启动活动B时的定义有 更高的优先级。</div>
					</div>
					<div data-role="collapsible" data-theme="a">
						<h5>使用清单文件</h5>
						<div>在Activity元素中有lanchMode属性。默认的属性是"standard".
							“singleTop"，如果一个活动已经存在当前任务栈中顶部时，系统将通过调用onNewIntent()将Intent定向传递到那一个活动的实例。
							而不是重新创建一个。这个活动可以被创建多次，每一个实例可以属于不同的任务。同一个任务也可以拥有多个实例（不能是在栈顶部）。
							"singleTask",顾名思义，即此任务栈中只有一个此活动的实例。新意图通过onNewIntent()传递给原来的实例。
							"singleInstance",即一个任务只有一个活动实例。在这个实例中启动的其它活动实例，都是在单独的任务栈中。</div>
					</div>
					<div data-role="collapsible" data-theme="a">
						<h5></h5>
						<p></p>
					</div>
					<div data-role="collapsible" data-theme="a">
						<h5>使用Intent标志</h5>
						<p>标志：FLAG_ACTIVITY_NEW_TASK同清单文件中的"singleTask"
							标志:FLAG_ACTIVITY_SINGLE_TOP,同清单文件中的"singleTop"
							标志:FLAG_ACTIVITY_CLEAR_TOP,在清单文件中没有对应值。
							此标志作用：如果此活动已经运行在当前的任务中，在此活动之后的其它活动实例将被
							销毁。意图将通过onNewIntent()传递给原来的活动实例。原来的活动实例现在将在任务栈顶部了。
							此标志经常与FLAG_ACTIVITY_NEW_TASK一起使用。</p>
					</div>
					<div data-role="collapsible" data-theme="a">
						<h5>处理连结关系（Handling affinities）</h5>
						<p>同一个应用的活动都有相同的连结关系。所以同一应用的活动都倾向于在同一个任务中。
							但是你可以修改这种关系使得不同的应用的活动有相同的连结关系。或者在同一个应用的活动
							拥有不同任务的连结关系。可以在清单文件中的activity元素中设置taskAffinity属性。</p>
					</div>
					<div data-role="collapsible" data-theme="a">
						<h5>清除任务栈（Clearing the back stack)</h5>
						<p>如果离开一个任务很长时间，系统会将此任务除根activity之外的所有活动清除。
							因为，在长时间之后，用户更喜欢丢弃他们之前的状态。下面有几个activity的属性可以修改这种默认的行为。
							alwaysRetainTaskState，顾名思义。 clearTaskOnLaunch.顾名思义。
							finishOnTaskLaunch，这个属性有点像clearTaskOnLaunch,但是它作用于单个的活动中。而非整个任务。

						</p>
					</div>
					<div data-role="collapsible" data-theme="a">
						<h5>启动一个任务（Start a task)</h5>
						<pre>
&lt;activity ... &gt;
    &lt;intent-filter ... &gt;
        &lt;action android:name="android.intent.action.MAIN" /&gt;
        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
    &lt;/intent-filter&gt;
    ...
&lt;/activity&gt;
				  	 			 </pre>
						显然如上设置将一个活动设置为一个任务的入口点。"singleTask",和"singleInstance"应当只应用在这样的入口点上。
						因为如果没有这样过滤器，当用户进入这个新任务，并按Home键离开之后，将没有入口能够进入了。
						如果你不想让用户可以返回一个活动，可以设置activity元素的finishOnTaskLaunch为"true"
					</div>
				</div>
				<!-- /themed container  end of 7.1.3 -->

				<div class="sub_sub_section">
					<h4 class="sub_sub_section_name">7.1.4&nbsp;管理活动的生命周期</h4>
					<p>通过实现回调方法来管理你的活动对于开发健壮及可扩展性的来说是非常关键的.
						活动所在的任务任务及回退栈及与其相关联的活动都对活动有直接的影响.一个活动一般处于三种状态:
					<dl>
						<df>Resumed(恢复状态)</df>
						<dd>活动在屏幕的前面,并且有用户焦点.这一概念有时被称为"运行中"(running)</dd>
						<df>Paused(暂停状态)</df>
						<dd>另一个活动在前面取得了焦点,但是这个活动还是可以看得见的.也就是说,另一个活动看起来在这个活动之上.并且另一个活动有部分透明或者没有覆盖整个屏幕.
							一个暂停的活动是完全活跃的(它的Acitivty对象还保存在内存中,并且维护了所以的状态及成员信息.并且依然依附在窗口管理器中.),当系统内存极低的时候,也有可能被杀掉.</dd>
						<df>Stopped(停止状态)</df>
						<dd>此活动完全被其它活动遮挡了(此活动现在在"后台"了).一个停止的活动依然是存活的(Activity对象保存在内存中,并维护了所有的状态及成员信息.但是并没有依附于窗口管理器上.)
							然而,它对于用户来说并不可见.并且当内存比较低时会被系统给杀掉.</dd>
					</dl>
					</p>
					<p>如果一个活动暂停或者停止了,系统可以通过让它结束(调用它的finish()方法)或者简单的杀死它的进程.
						当这个活动被重新打开之后(被结束之后或者杀掉之后.),它必须再重新创建.</p>

					<div data-role="collapsible" data-theme="a">
						<h5>实现生命周期回调方法</h5>
						<div>
							<p>
								当一个活动在上面提到的状态转换的时候,将会通过多种回调方法得到通知.当你的活动的状态改变的时候,你可以重写这些回调钩子方法做一些适当的工作.
								下面的基本代码逻辑包括了基本的生命周期方法:</p>
							<pre>
public class ExampleActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 活动创建时调用
    }
    @Override
    protected void onStart() {
        super.onStart();
        // 活动将被显示在屏幕上时调用.
    }
    @Override
    protected void onResume() {
        super.onResume();
        // 活动可视时调用(它现在是"resumed"的了!)
    }
    @Override
    protected void onPause() {
        super.onPause();
        // 另一个活动取得了焦点(此活动进入暂停状态.)
    }
    @Override
    protected void onStop() {
        super.onStop();
        // 活动不可见(此活动进入了停止状态.)前调用.
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 此活动将被销毁时调用
    }
}
				  	 	</pre>
							<p>
								<strong>注意:</strong>在你实现的上面的生命周期中的方法中,在你做任何事情前,你应当调用父类的实现,正如上面的例子那样.

							</p>
							<p>放在一起,这些方法定义了一个活动的整个生命周期.通过实现这些方法,你可以监视在你活动生命周期中的三个循环:
							<ul>
								<li>活动的<strong>完全的生命时间</strong>在调用<code>onCreate()</code>到调用<code>onDestory()</code>之间.你的活动应当在<code>onCreate()</code>执行全局状态的设置(例如设置布局).在<code>onDestroy()</code>方法中释放所有其他资源.例如,如果你的活动有一个用来从网络中下载数据的后台线程.最好是在<code>onCreate()中</code>创建,并且在<code>onDestory()</code>上停止这个线程.
								</li>
								<li>活动的<strong>可视的生命时间</strong>在调用<code>onStart()</code>到调用<code>onStop()</code>之间.在这段时间中,用户可以看见这个活动并与之交互.例如,当一个新的活动启动的时候此活动将不再可见.在这些方法之中,你可以维护活动想要展现给用户看的资源.例如你可以在<code>onStart()</code>注册一个<code>BroadcastReceiver</code>(广播接收者)来监视影响你的UI的变化.并在<code>onStop()</code>的时候注销它,此时用户已经不能看见你显示了什么了.当活动可视和不可视中转换时,在活动的整个生命周期中系统也许会多次调用<code>onStart()</code>和<code>onStop()</code>at
								</li>
								<li>活动的<strong>前台的生命时间</strong>在调用<code>onResume()</code>到调用<code>onPause()</code>之间.在这段时间里,这个活动在所有的活动前面并拥有用户的输入焦点.一个活动能够频繁的进入或者退出前台--例如,当设备将休眠或者一个对话框出现的时候<code>onPause()</code>将会被调用.因为这个状态的经常转换.在这两个方法中的代码应当比较轻量,以免减慢切换速度使用户等待.
								</li>
							</ul>
							</p>
							<p>
								下图说明了活动在各种状态中的执行路径及循环.矩形代表了当活动在状态间切换时你可以实现回调以执行某些操作的方法. 
														<div class="img_wrapper">
								<img
									src="drawables/activity_lifecycle.png"
									title="activity_lifecycle" />
					<p class="pic_desc">图&nbsp;7.1&nbsp;Androic生命周期示意图</p>
					</div>
							</p>

						</div>
					</div>
				</div>
				<!--  end of7.1.4 -->

			</div><!--  end of 7.1 -->
			
			
				<div class="sub_section intent_intent_filter">
					<h3 class="sub_section_name">7.2&nbsp;Intent及Intent&nbsp;Filter</h3>
					如果有JavaWeb的开发经验，则可以简单的将Intent看作一个高级的HttpRequest，将Intent&nbsp;Filter看作是一个Servlet的过滤器。
					但是其实Android的设置确实更高级，高复杂些。Intent中文可以称为意图，Intent&nbsp;则过意图过滤器。
						<div class="sub_sub_section" class="ui-body ui-body-a">
							<h4 class="sub_sub_section_name">7.2.1&nbsp;意图对象</h4>
							<p>Intent是一组信息的集合.
								(它包含了接收这个意图组件所需要的信息，如要执行的操作，及需要的数据。还有Android系统所需的
								信息，如哪种类型的组件可以处理这个Intent,及一些如何启动一个目标活动的指令。） 原则上包含下面的：</p>
							<div data-role="collapsible" data-theme="a">
								<h5>组件名 (Component name)</h5>
								<p>处理此意图的组件的名字。此字段是一个ComponentName对象（由一个组件的全类名，
									例如“com.example.project.app.FreneticActivity”）和在应用程序清单的清单中声明的包名。如（"com.example.project"）
									组件名是可选，如果设置了名字，意图对象将传递给这个目标类的一个实例。如果没有设置，android使用意图对象中包含的其它信息来确定目标对象。
									参见Intent
									Resolution.可以通过setComponent(),setClass(),或者setClassName()，通过getComponent().
								</p>
							</div>
							<div data-role="collapsible" data-theme="a">
								<h5>操作(Action)</h5>
								<div>
									一个声明要执行操作的字符串。或者在广播意图中，action发生的地方及广播的地方。Intent类定义了一系列的action常量。
									包括下面这些。
									<ul>
										<li><code>ACTION_CALL</code>，用于activity，表示打电话</li>
										<li><code>ACTION_EDIT</code>，用于activity,显示数据以便让用户编辑</li>
										<li><code>ACTION_MAIN</code>用于activity,启动某一个任务的初始activity，没有数据输入，也没有数据返回</li>
										<li><code>ACTION_SYNC</code>用于activity,从服务器上同步数据到设备</li>
										<li><code>ACTION_TIMEZONE_CHANGED</code>用于broadcast receiver,设置中的时区改变了</li>
									</ul>
									Intent类还包含了其它众多的ACTION，在API中也有其它的ACTION。应用也可以定义自己的ACTION字符串，用于在自己的应用中激活组件。
									如"com.example.project.SHOW_COLOR"
									,这个action将很大程度中决定data和extras字段的结构。一系列参数及返回值。因此应当尽可能指定action名。
									并且和Intent的其它字段紧密结合起来。换句话说，应该为处理意图的组件定义整个协议而不是单独定义一个action.
									action使用setAction()定义。使用getAction（）读取。
								</div>
							</div>
							<div data-role="collapsible" data-theme="a">
								<h5>数据(Data)</h5>
								<p>data的URI，和data的MIME类型。不同的action以不同的data声明结对。例如，action字段是ACTION_EDIT,数据字段将包含将要编辑的文档的
									URI,如果action是ACTION_CALL,数据字段将是tel:URI带着将要拔出的号码。同样如果action是ACTION_VIEW,这个data
									field是一个http:URI,
									接收的activity将决定下载显示这个URI所指向的数据。知道要处理的数据的类型（MIME类型）的是很重要的
									。很多情况下，类型可以从URI中推断出来，也可以在Intent
									对象中显示设计。数据使用setData()指定（URI），用setType()指定它的MIME类型，通过setDataAndType()
									来同时设置。通过，getData()读取URI，通过getType()读取类型。</p>
							</div>
							<div data-role="collapsible" data-theme="a">
								<h5>类别(Category）</h5>
								<p>
									一个用于指定处理Intent的组件的类型的字符串。Intent类中定义了一些category的常量。</p>
									<ul>
										<li>
											<code>CATEGORY_HOME</code>
											此activity显示主屏幕。
										</li>
										<li>
											<code>CATEGORY_LAUNCHER</code>
											此activity可以是某一个任务的初始activity。在顶层的应用启动器中列出。
										</li>
										<li>
											<code>CATEGORY_PREFERENCE</code>
											目标activity是偏好设置
										</li>
									</ul>
									可能通过addCategory（)为意图对象添加类别，removeCategory()删除之前添加的类型，getCategories（）返回对象中所有的类型集。
								
							</div>
							<div data-role="collapsible" data-theme="a">
								<h5>扩展数据（Extras）</h5>
								<p>传递给处理意图组件的额外键值对信息。例如如果你创建一个SHOW_COLOR的action，那么，颜色值将在extra中的键值对中设置。
									Intent对象有一系列的put...()方法用来插入各种类型的extra数据，同样有一系列的get...()方法。</p>
							</div>
							<div data-role="collapsible" data-theme="a">
								<h5>标志(Flags）</h5>
								<p>各种类型的标志，指示android系统如何启动一个活动（如活动属性
									哪一个任务）和启动之后如何处理（如，它是否是一个最近活动），所以的这些标志都定义在Intent class中。</p>
							</div>
							android系统与应用程序协同工作来发布Intent
							Object到面向系统的广播以激活系统定义的部件。
						</div>
						<!-- /themed container end 7.2.1-->

						<div class="sub_sub_section ui-body ui-body-a">
							<h4 class="sub_sub_section_name">7.2.2&nbsp;意图解析及过滤</h4>
							<p>Intent可见被分成两组，显示Intent,和隐式Intent.显示Intent用名字指定目标组件。多用于应用程序内部调用。
								隐式Intent，的目标组件为空。通过用于激活其它应用程序的组件。
								为了告知系统能处理何种隐式的意图，活动，服务，广播接收者，可以有一个或者多个过滤器。</p>
							<ul>
								<li><strong>显式意图解析</strong>通过名字</li>
								<li><strong>隐式意图解析</strong>由于没有指定的目标组件。系统会通过比较一些活动的过滤器来确定可以处理这些意图的组件。
									一个活动如果没有设置过滤器，那它只能接收显示的意图。 意图过滤器考查下面三个方面：action,data,category</li>

							</ul>
							<p>如果没有解析出目标组件将抛出异常。如果有多个则让用户选择。</p>


							<p>
								<strong>Intent filters过滤器</strong>一个过滤器是一个IntentFilter的实例，但是因为Android
								系统必须在启动组件之前知道组件 的特征。Intent filters通常不在Java代码中设置，而是在清单文件中设置。
								Intent-filter有三个匹配测试集。分别是Action test，Category test和，Data test
							</p>
							<div data-role="collapsible" data-theme="a">
								<h5>动作检测</h5>
								<div>
									intent-filter元素有一列action子元素。例如：
									<pre>
&lt;intent-filter . . . &gt;
    &lt;action android:name="com.example.project.SHOW_CURRENT" /&gt;
    &lt;action android:name="com.example.project.SHOW_RECENT" /&gt;
    &lt;action android:name="com.example.project.SHOW_PENDING" /&gt;
    . . .
&lt;/intent-filter&gt;			</pre>
									action应当至少有一个，否则将阻塞所有的意图。另一方面，没有指定action的意图对象将自动通过测试－只要过滤器至少有一个action
									.
								</div>
							</div>
							<div data-role="collapsible" data-theme="a">
								<h5>类别检测</h5>
								<div>
									<pre>
&lt;intent-filter . . . &gt;
    &lt;category android:name="android.intent.category.DEFAULT" /&gt;
    &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
    . . .
&lt;/intent-filter&gt;			</pre>
									注意在清单中文中使用的全名。例如，android.intent.category.BROWSABLE对应类中的
									CATEGORY_BROSABLE常量。同理android.intent.action.EDIT对应ACTION_EDIT.
									为了通过测试，在意图对象中的每一个类别都必须在过滤器中匹配一个类别。过滤器可以列举额外的类别，但是
									不能忽略在意图中的类别。因此，原则上来看，无类别的意图都将通过测试。有一个例外，android将所以的隐式意图传递给startActivity()
									,就好像他们包含至少一个类别:"android.intent.category.DEFAULT",因此，接收隐式意图的活动在过滤器中应当包含"android.intent.category.DEFAULT"
									(有"android.intent.action.MAIN"和"android.intent.category.LAUNCHER"的除外。)
								</div>
							</div>
							<div data-role="collapsible" data-theme="a">
								<h5>数据检测</h5>
								<div>
									<pre>
&lt;intent-filter . . . &gt;
    &lt;data android:mimeType="video/mpeg" android:scheme="http" . . . /&gt; 
    &lt;data android:mimeType="audio/mpeg" android:scheme="http" . . . /&gt;
    . . .
&lt;/intent-filter&gt;			</pre>
									data元素是可选的，即0到多个。每一个data元素指定了一个URI和数据类型(MIME 媒体类型)
									每一个URI包含scheme,host,port,及path几个属性。scheme://host:port/path
									data元素的type属性中的子类型字段可以可能使用通配符"*"例如。"text/＊"，"audio/*"
								</div>
							</div>
							<!--  end of data test -->
						</div>
						<!-- /themed container end of 7.2.2 -->

				</div>
				<!--  end of 7.2 -->
			
			
		</section><!--  end of 7 -->
		
	<section>
		<h2 class="section_name">8&nbsp;&nbsp;设计中问题及解决方案</h2>
		<div class="sub_section">
			<h3 class="sub_section_name">8.1&nbsp;基础数据的缓存与数据同步</h3>
				<div data-role="collapsible" data-theme="a">
					<h4>实际问题与需求</h4>
					<p>
					 在我开发系统中，用户的操作随时都在与数据打交道，如菜品数据，这是经常使用的最基础的数据。
					 一开始是，当用户选择某一个小类时（假设为‘A'），就会向服务器请求’A'类下的所有菜品数据，然后显示给用户。
					 这在网络条件比较好的情况下没有什么问题。虽然我们应用的针对的环境是局域网，但是由于是无线局域网受到无线信号，路由产品
					 及设备本身质量的影响，网络连接很容易出现不稳定的情况。所以在请求数据时，就会经常出现请求数据失败的情况。造成的用户体验非常不好。
					</p>
				</div>
				<div data-role="collapsible" data-theme="a">
					<h4>对问题的思考</h4>
					<p>
					  针对上面的问题，解决方案就是，提前将菜单数据下载下来，存储在内存缓存中。（这里同时带来的有另外一个问题就是缓存如果过多，
					  移动设备内存有限会导致应用崩溃）。
					  这里同时还有一个问题，就是每次打开应用都要去请求一次数据，这个请求过程同样时比较花时间的。
					  如果用户打开关闭应用比较频繁，就会造成非常不好的体验。
									缓存与数据同步初看起来好像是两个矛盾的对立面。因为缓存是目的是尽量减少数据更新。数据同步则希望数据尽可能的更新。
				缓存是为了解决数据读取性能的大量消耗而产生的。
				我们的目的是要保证数据一致性。关键问题是如何减少数据同步的次数。
					</p>
				</div>
			<div data-role="collapsible" data-theme="a">
					<h4>解决方案</h4>
					<p>
					  最后目前采用的解决方案，首先android对SQLite数据库有完整的支持。所以每次下载的数据存储在数据库中。
					   如何保证数据库中数据是最新的呢。当用户每次启动应用时，就会拿本地的一个最新菜品数据的时间截和服务器上的最新菜品数据时间截对比。
					   如果服务器中菜品有更新。则时行同步，否则不同步。这样就保证了数据的一致性。由于菜品是基础数据，如果数据基本不变的话，则大概减少了向服务器
					   请求下载菜品数据的次数。
					   然后，针对对SQLite读取数据也是有一个查询过程，有些时候也比较消耗时间，为了使应用使用更顺畅，一是将SQlite中查询字段创建索引。二是可以在启动应用时，
					   在内存中建立以菜品小类为单元的。缓存数据集。这样就基本解决了这个问题了。
					</p>
				</div>
		</div><!--  end of 8.1  -->
		
		<div class="sub_section">
			<h3 class="sub_section_name">8.2&nbsp;动态即时数据的缓存与同步</h3>
				<div data-role="collapsible" data-theme="a">
					<h4>实际问题与需求</h4>
					<p>
					 在点菜过程中，餐厅中桌子是不停的在动态的变化的。这就要求每次使用应用的服务员打开桌子状态界面的时候，看到的都应该是最新桌子状态。
					 这就要求每次都要去下载桌子状态数据。但是如果桌子比较多，数据量也就很多。
					 在刷新桌子状态数据的时候容易出现问题。
					</p>
				</div>
				
				<div data-role="collapsible" data-theme="a">
					<h4>对问题的思考</h4>
					<p>
					 区别于上面的问题，这里的数据是动态在更新的，一个最初的办法是检测桌子状态是否发生改变，改变才更新，不改变就不更新。但是对于即时数据来说，这种
					 检测没有多大的意义。因为桌子状态在不停的动态变化，每次检测返回的结果几乎都需要更新数据。所以检测，没有什么意义。反而增加了检测的时间成本。
					 对此办法的改进办法是，如果桌子状态有一个最新更新时间的时间戳，在本地保存最新的更新桌子状态的时间戳，这样每次下载的桌子数据就是，
					 比之前时间戳更新的时间的桌子数据了。这样减少了下载量。也算是能够很好的解决当前问题。
					</p>
				</div>
				<div data-role="collapsible" data-theme="a">
					<h4>解决方案</h4>
					<p>
					上面思考中，每次去下载发生了改变的数据。一般情况下是可以工作的。但是在我这里却遇到麻烦了。原因是，一些情况下，桌子状态发生了改变，桌子状态数据库记录的
					一个对应时间戳就会更新。但是有些情况下，就算桌子状态变化了时间戳还是没有变化。于是下载就会失效。还有一个重要的原因是，
					桌子状态是当用餐等交互信息时，才会出现在有对应的桌子状态信息记录，如果用餐这一动作完成，记录删除，也会造成下载更新失败。这是系统原来设计的遗留问题。
					但是为了兼容老的系统，所以只有在不更新系统后台数据库的情况下设计。
					所以，当前的解决方案是：
					在应用启动的时候，在后台启动一个后台定时线程，经过一个设置的时间(如10秒)就向服务器请求一次桌子状态数据，并存入本地缓存。
					在用户打开应用的桌子状态界面是，就用缓存的数据来构造用户界面。如果用户在本地进行了对桌子状态有更改的操作后，则更新对应缓存中的桌子状态信息。
					</p>
				</div>
				
		<div class="sub_section">
				<h3 class="sub_section_name">8.3&nbsp;多线程与Socket通信</h3>
				<div data-role="collapsible" data-theme="a">
					<h4>实际问题与需求</h4>
					<p>
					在上面提到的数据同步及向服务器请求数据中，我们使用了多个线程，系统一开始使用的一一个Tcp连接来处理请求。
					这样在多个线程共享一个Socket连接的时候，容易出错。但是，又需要能够支持多个线程来处理数据。
					</p>
				</div>
				<div data-role="collapsible" data-theme="a">
					<h4>对问题的思考</h4>
					<p>
					  Socket连接是一个比较重量级的连接。如果每次发送请求交互都重新创建连接，会使网络的性能大打折扣。
					  而且Socket的IO是以阻塞的方式时行的。所以如果只有一个Socket连接的话，在网络请求较多的情况下，网络的性能会进一步下降。
					</p>
				</div>
				<div data-role="collapsible" data-theme="a">
					<h4>解决方案</h4>
					<p>
					在这种情况下，一种通用的解决方案就是使用Socket连接池。使用连接池一般有三个理由<sup>[14]</sup>：
					</p>
					<ol>
						<li>创建连接的成本是非常高的，通过使用连接池可以在重复利用连接的时候增进性能。</li>
						<li>它程序的设计更容易，如果没有连接池，则必须得考虑如何在利用连接，而不至于出错。</li>
						<li>连接池可以使得多线程的操作变得非常的容易。</li>
					</ol>
					<p>
					 对于连接池这么一个经常使用技术，可用一些通过的连接池来实现业务特定的连接池。但是自己实现也不难。
					 主要也就是四个步骤：一是，初始化连接池；二是，获得空闲的连接；三是,回收连接；四是，清理连接。
					 一个简单的连接池的实现见附录一。
					</p>
				</div>
		</div><!--  end of 8.3 -->
		
		<div class="sub_section">
			<h3 class="sub_section_name">8.4&nbsp;响应性设计与AsyncTask</h3>
			<p>
				在Android3之前如果写在UI线程（即主线程）中进行网络操作，如向服务端请求数据。应用运行正常，但是在android3及之后的版本（并且目标SDK版本是android3及之后的版本）则会抛出异常：
				<code>android.os.NetworkOnMainThreadException</code>
				
			    我们知道网络操作是不稳定，并且耗时的。如果在UI线程中进行网络操作，将阻塞UI线程，一般的行为表示就是让用户觉得程序卡在那里了。
			    造成用户体验不好。例如我们要在用户点击的某个图片的缩略图的时候，向服务器请求对应图片的数据，我们也许会这样来将网络操作放在后台线程中。
			</p>
			
			<pre>
public void onThumbClick(View v){
	 final String imgUrl = (String) v.getTag();
	new Thread(new Runnable(){ 
		public void run(){
			Bitmap b = loadImageFromServer(imgUrl);
			mMenuxImage.setImageBitmap(b);
		}
	}).start();
}	
			</pre>
			<p>
			上面的代码看起来很好，但是它违背了Android设计中的另外一条原则就是，不要在UI线程之外访问Android的UI控件。而上面的代码就在
			后台线程中修改了ImageView的一个对象。这会导致未定义的行为，并且可能会消耗大量时间。<sup>[17]</sup>
			但是，有时候我们又需要在后台线程中访问UI组件。正如上面的的代码所做的。幸好Android平台提供了几种在其它线程中访问UI线程中的方法。
			如：1.使用<code>Activity.runOnUiThread(Runnable)</code>，2.使用View类提供的<code>View.post(Runnable)</code>和<code>View.postDelayed(Runnable,long)</code>
			我们使用方法2,将上面的代码修改如下 ：
		 </p>
		<pre>
public void onThumbClick(View v){
	 final String imgUrl = (String) v.getTag();
	new Thread(new Runnable(){ 
		public void run(){
			Bitmap b = loadImageFromServer(imgUrl);
			mMenuxImage.post(new Runnable(){
				public void run(){
				mMenuxImage.setImageBitmap(b);
				}
			});
			
		}
	}).start();
}
		</pre>
		 <p>
		 上面的代码，已经是线程安全的了，但是看起来有一点的难看。如果代码更复杂点，可能就更难看了。
		 在Android的世界里，解决上面的问题的最好方法就是扩展AsyncTask类了。
		 AsyncTask专门有一个方法，可以用来在后台线程执行某些操作，然后将操作结果返回给UI线程中的执行的方法。
		 AsyncTask中主要的方法说明如下：
		 </p>
		 <ul>
		 	<li><code>doInBackground()</code>，AsyncTask类会保证这个方法在一个后台线程中运行。运行结果将传递给onPostExecute()。</li>
		 	<li><code>onPreExecute,onPostExecute(),onProgressUpdate()</code>在UI线程中执行。</li>
		 	<li><code>onProgressUpdate()</code>，在doInBackgroud()中调用publishProgress()则可以在UI线程中调用onProgressUpdate，顾名思义，这个方法用来报告后台线程现在处理到什么进度了。</li>
		 </ul>
		 上面的示例代码使用AsyncTask改写之后，如下：
		<pre>
private class DownloadImageTask extends AsyncTask&lt;String,void,Bitmap&gt;{
	@Override
	protected Bitmap doInBackground(String... urls){
		return loadImageFromServer(urls[0]);
	}
	@Override
	protected void onPostExecute(Bitmap result){
		mMenuxImage.setImageBitmap(result);
	}
}
private void onThumbClick(View v){
	new DownloadImageTask().execute((String)v.getTag());
}
		</pre>
		从上面的代码可以看出使用了AsyncTask之后，代码的可以变得很清晰了。可见AsyncTask()确实是在Android平台进行如网络等后台操作的理想实现模式。
		
		</div><!--  end of 8.4 -->
		
		
	</section><!--  end of section 8 -->

		<section>
			<h2 class="section_name">9&nbsp;&nbsp;Android开发中的重构实践</h2>
			     <div class="sub_section">
					<h3 class="sub_section_name">9.1&nbsp;重构出一个实用的Toast工具类</h4>
					<p>Toast是Android平台中三大通知技术中的一种。下图是一个闹钟应用，当设置启用闹钟时的屏幕截图。</p>
					<div class="img_wrapper">
					<img src="drawables/toast.png" title="toast" />
					<p class="pic_desc">图&nbsp;9.1&nbsp;当设置启用闹钟时显示有Toast的屏幕截图</p>
					</div>
					
					<p>一般使用Toast的方式如下：</p>
					<pre>
Toast.makeText(getApplicationContext(),"hello,world!",Toast.LENGTH_SHORT).show();
					</pre>
					但是写得多了也就觉得烦了，虽然上面由于makeText支持链式调用，所以可以一行代码搞定。
					但是还是觉得长。但是怎么让代码变得更短，而且语义还很明显呢？经过思考有了以下代码：
					<pre>
public class ToastUtils {
	public static void showShort(Context context, String message) {
		Toast.makeText(context,message,Toast.LENGTH_SHORT).show();
	}

	public static void showLong(Context context, String message) {
		Toast.makeText(context,message,Toast.LENGTH_LONG).show();
	}


}
					</pre>
					显然，上面主要是将Toast.LENGTH_SHORT这个参数的语义，转移到了一个方法的名字上。
				现在显示一句"hello,world"可以使用这样的代码了。：
<pre>
	ToastUtils.showShort(getApplicationContext(),"hello,world")；
	// 如果在onCreate()中已经将有Context mContext = getApplicationContext();语句
	//那么可以更简单点：
	ToastUtils.showShort(mContext,"hello,world")；
</pre>
  对于上面的，有一个没有语义的参数就是mContext，但是能不能将mContext放到ToastUtils类中作为一个静态变量。
  答案是否定的，因为那样就将Acitivty的Context对象给泄漏了。会造成内在泄漏。所以一般在非Acitvity环境下，使用Context对象
  适合，在需要使用Context的方法中将此对象作为参数传递进去。方法执行完对象就释放了。
  <p>
  在没有其它需求的情况下，上面的简单的ToastUtils工具类看似很不错了。
  但是，为了软件的国际化我们经常在显示字符串时，需要使用资源ID，而不是字面量值。
  如下就变成了下面的代码：
  </p>
 					<pre>
public class ToastUtils {
	public static void showShort(Context context, int message) {
		Toast.makeText(context,message,Toast.LENGTH_SHORT).show();
	}

	public static void showLong(Context context, int message) {
		Toast.makeText(context,message,Toast.LENGTH_LONG).show();
	}
	public static void showShort(Context context, String message) {
		Toast.makeText(context,message,Toast.LENGTH_SHORT).show();
	}

	public static void showLong(Context context, String message) {
		Toast.makeText(context,message,Toast.LENGTH_LONG).show();
	}


}
					</pre>
<p>
	现在发现需求变了，因为Toast默认显示在屏幕中间，而我们喜欢将Toast显示在屏幕靠近下面的地方。于是，我们决定将
	上面中的方法改成下面这样的：
</p>
<pre>
public static void show(Context context, String text, int duration) {
	Toast toast = Toast.makeText(context, text, duration);
	toast.setGravity(Gravity.CENTER, 0, 80);
	toast.show();
}
</pre>
然后我们决定将上面的代码，应用到上面的4个方法中。在学习重构一书后，我有了在复制代码时考虑使用抽取方法的重构，于是代码变成了下面的了。
<pre>
	public static void showLong(Context context, String message) {
		show(context, message, Toast.LENGTH_LONG);
	}

	public static void showShort(Context context, String message) {
		show(context, message, Toast.LENGTH_SHORT);
	}

	public static void showLong(Context context, int textId) {
		show(context, textId, Toast.LENGTH_LONG);
	}

	public static void showShort(Context context, int textId) {
		show(context, textId, Toast.LENGTH_SHORT);
	}

	public static void show(Context context, String text, int duration) {
		Toast toast = Toast.makeText(context, text, duration);
		toast.setGravity(Gravity.CENTER, 0, 80);
		toast.show();
	}

	public static void show(Context context, int textId, int duration) {
		show(context,context.getString(textId),duration);
	}
</pre>
<p>有了上面的重构实践之后，就能很容易的写出简洁精练，ToastUtils类代码了。完整的类代码还包括了整个类中，显示不同状态下自定义布局的Toast消息。
见附录二。</p>
	       </div>
	       
	       	<div class="sub_section">
				<h3 class="sub_section_name">9.2&nbsp;会说话的代码</h4>
					<p>
					如果只是写一个简单的hello,world程序，那代码也许是给计算机看的。但是如果写一个真正的软件。那么经常看代码的不是计算机，而是人。
					所以，如果代码可读性好的话，就算是自己写的代码，过了一段时间也许连自己也不清楚代码到底做了什么事情了？更何况如果维护软件的
					是其它人呢？一般人，认为为了维护提高可读性的方式是给代码添加注释。但是，个人认为给代码添加注释，有两个不好的方面。
					</p>
					<ul>
						<li>如果注释写得不清楚，那么还是难以让人理解。</li>
						<li>如果，代码修改之后，注释没有同步修改，还是会造成问题。</li>
					</ul>
					所以我认为，写注释是，写出可读性代码的最后一招。
					<p>
						写出可读性好的代码，对于代码本身来说，可以从两方面来改善，一是命名，二是适当改变代码的逻辑结构。
					</p>
					
					<div class="sub_sub_section">
						<h4 class="sub_sub_section_name">9.2.1&nbsp;让代码说话</h4>
						<p>好的代码是会说话的。所以当一看到好代码，它就会告诉你它想做什么。
							它说话的方式主要是通过它的名字来跟阅读它的人交流。
							对于Java程序来说。有名字的元素主要有五种。
							包名，类名，字段名，方法名，变量名。
							在写代码时候，要不断的注意自己所用的名字，如果一旦发现原来的名字不怎么好，
							可以使用重命名这一重构来给他选择一个好的名字。开发者常用的IDE，Eclipse对这一重构支持很好。
							（对于公开给外部使用类的话，则不能使用重命名的方法，为了向后兼容，应当将原来的名字标记为@Dreprecated。
							然后再提供新名字使用。
						</p>
						<div data-role="collapsible" data-theme="a">
							<h5>包名会说话</h5>
							<p>
								榜样的力量无穷的。好地包名的设计可以参考一些优秀的开源项目。
								最显著，作为android开发者，可以参考Java类库的包名命名，android框架的包的命名。
								好的包名的标准，应该是能够顾名思义，一目了解。首先是应该遵守Java关于包名的规范。							
							</p>
							<p>
								对于android开发，或者对于现在的应用开发来说一般会遵循MVC模式来开发。
								那么就可以按照MVC模式分层来对包进行设计。
								如自己的域名是me.banxi，并且自己应用名称为drawdroid
								那么控制层类的包名就可以是me.banxi.drawdroid.controller或者直接是me.banxi.drawdroid.activity
								因为Activity就是起到Controller的作用。
								而数据访问层中的实体类，数据模型类就可以放在me.banxi.drawdroid.model或者
								me.banxi.drawdroid.domain或者me.banxi.drawdroid.domain，这些名字都能表达一样的意义。
								就看个人喜好了，但是同一个项目应该保持统一。
								如果有一些自定义的android控件则可以放到me.banxi.drawdroid.widget或者
								me.banxi.drawdroid.view中。与android中包名意义对应。如果写的控件或者view是通用的。则可以放在
								me.banxi.widget或者me.banxi.view中。表示这些控件是可以在其它项目使用的。
								甚至比较好的方式是把这些自定义的通用控件独立出来作为一个库项目来在其它项目中引用。
							</p>
					   	</div><!--  package -->
						   	<div data-role="collapsible" data-theme="a">
								<h5>类名会说话</h5>
								<p>
								类是对现实事件事件是抽象。有时也是对本身是抽象的事件的再抽象。
								所以一般使用名词来表示某一个类。也可以用物以类聚的方法来处理某些
								不具备抽象意义的类，如某一些功能方法集合。完成某些抽象任务的方法集合放在一起。
								有一些类是比较好命名的。
								<ul>
									<li><strong>实体类</strong>，找对应的英文单词就可以了。对于英文不好的，可以多多比较下英文单词看那个比较适合一些。</li>
									<li><strong>通过继承的类</strong>，通过继承的类，根据自己的需要仿照所继承的类的名字，就可以得到一个合适的名字了。
									如Activity类是，android中开发中控制器的最基本类，集成了ListView功能的类就叫ListActivity。集成Tab效果的类就叫TabActivity。</li>
									<li><strong>通过实现的接口</strong>，如果类只是简单的实现了某个接口。那么可以简单的在接口名后面加过Impl，如有一个PersonDao的接口。那么在只有一个
									实现的时候，其类名可以是PersonDaoImpl。
								</ul>
								</p>
						   </div>
						   	<div data-role="collapsible" data-theme="a">
								<h5>字段会说话</h5>
								<p>
								在面向对象的世界中，字段通常是对象的属性的表示。
								通常是直接写成对应的属性名。同类字段最好是具有某种属性。
								并且以关键特性开头。如有些作为键名的常量就是可以以KEY_作为前缀。
								遵守一般的编程习惯如常量使用全部大写，多个单词以下划线分开。
								对于基于类型的变量，需要选择表现出相关意义的变量名。
								尽量保证完整的意义的名字，不能随便使用简写。对于java开发来讲。
								就算写时候用的名字比较完整。占用类存多一点点，但是在发布应用之前，可以使用
								Java代码混淆工具即代码压缩工具如ProGuard来完成。这个的效果，比自己费改心来想一个简短的名字
								效果好得多。所以字段名，尽量让它表达多自己应该有的意义出来。
								</p>
								<p>
								对于一开始没有好的名字时，应该使用重构来给一个好的名字，如果是共开的API的话，则
								可以将老的名字标记为@Dreprecated，然后提供新名字。如Android中的DialogInterface中，
								如下：
								</p>
								<pre>
    /**
     * The identifier for the positive button.
     */
    public static final int BUTTON_POSITIVE = -1;

    /**
     * The identifier for the negative button. 
     */
    public static final int BUTTON_NEGATIVE = -2;

    /**
     * The identifier for the neutral button. 
     */
    public static final int BUTTON_NEUTRAL = -3;

    /**
     * @deprecated Use {@link #BUTTON_POSITIVE}
     */
    @Deprecated
    public static final int BUTTON1 = BUTTON_POSITIVE;

    /**
     * @deprecated Use {@link #BUTTON_NEGATIVE}
     */
    @Deprecated
    public static final int BUTTON2 = BUTTON_NEGATIVE;

    /**
     * @deprecated Use {@link #BUTTON_NEUTRAL}
     */
    @Deprecated
    public static final int BUTTON3 = BUTTON_NEUTRAL;								
								</pre>
						   </div>
						   	<div data-role="collapsible" data-theme="a">
								<h5>方法会说话</h5>
								<p>
								  方法，应该抽象成完成某一步骤的表述。方法名要很好表达出，他做的是什么。
								  如果在开发前先写了伪代码，那么一般伪代码的中的一行一般就对应一个方法。
								  方法会说话，是让整个应用代码说话的关键。
								  如果有一些地方的代码，你觉得需要写注释了，那么就试着将那些代码提取出来，这个时候，
								  选择一个适合的方法名那么方法名就是注释了。有些时候，就算比较简单的代码，也许写的时候，
								  觉得很简单不需要一个方法，也不需要注释，但是过了一段时间，也许，需要稍微想一下才能理解代码的意思。
								  但是如是选择使用一个方法来实现，那么就算过了一些来看，也是很清楚显然的能够理解代码的意思了。
								  所以很多时候，方法名是对方法最好的注释。
								  比如我们需要在一个绘制图形的方法中计算两点之间的距离。
								  因为<code>d=sqrt((x1-x2)^<sup>2</sup>+(y1-y2)^<sup>2</sup>)</code>
								  所以我们写出的代码是这样的：</p>
								  <pre>
double distance = Math.sqrt(Math.pow((x1-x2),2)+Math.pow((y1-y2),2))；
					 			 </pre>
								  <p>上面的代码中已经算是因为distance这个变量名，及x1,x2这些我们在数学中常用的名字，所以看代码的时候，
								  只要稍微想一下，应该就能知道它是两点之前的距离的。
								  但是仔细看看，上面的代码看起来还是挺不好看的。多个方法的调用，N多括号。
								  但是用一个方法就不同了：</p>
								  <pre>
float distance = distanceOf(x1,y1,x2,y2)；						  
/**
 * 计算两点之间的距离 点1 (startX,startY),点2 (endX,endY)
 */
public static float distanceOf(float startX, float startY, float endX, float endY) {

	float w = Math.abs(startX - endX);
	float h = Math.abs(startY - endY);

	return (float) Math.sqrt(Math.pow(w, 2) + Math.pow(h, 2));
	
}
								  </pre>
								 <p> 显然在使用distanceOf()方法，这个方法的名字，就很好的说明，代码所做事情，比单纯的代码加注释好很多。
								  如果实在还需要注释，那么可以将注释写在方法中。
								  如果有多个地方需要计算两点之间的距离。那么使用方法的优势就更突出了。因为最原始的方法需要将上面的代码
								  到处拷贝。如果，如果要修改的话，那么也就需要到处修改了。
								  比如，现在我们知道Android框架中提供的几个数据计算函数，比java.lang.Math类中提供的性能更高。
								  而且我们使用的变量的Float型的。所以我们想要使用android.util.FloatMath。
								  那么修改就只需要修改distanceOf()这个方法。其它的方法不需要修改。这个带来的好处是不言而喻的。
								  </p>
								  <pre>
return FloatMath.sqrt(Math.pow(w,2)+Math.pow(h,2));)
								  </pre>
								  
								
						   </div>
						   	<div data-role="collapsible" data-theme="a">
								<h5>变量会说话</h5>
								<p>
								在方法中，变量仿佛是活跃在代码中精灵。
								</p>
								<p>
							   这里所指的变量是指，局部变量有参数。如果变量没有好一点的名字，它可能就会给我们带来麻烦，捣点小乱。
								因为没有好一点的名字给阅读上造成很大的麻烦。
								一般我们将参数也当成是一种变量 。好的参数名，对于调用的方便确实是有
								很大的作用的。特别是在刚刚学习的时候，或者对于某某API不熟悉的时候，
								调用那些API，如果API参数比较友好，在调用上我们就能很快的确定，到底应该传递什么参数。
								</p>
								
								<p>
								 一般会选择一些比较短小但又有一定意义的名称。通过是某一个完全名称的简短名称。有些时候需要根据上下文，
								 及一些简单的约定的认识。如上面的示例方法distanceOf中的w和h一看就知道是width和height和简写。
								 这个很容易看出来。如果某一个完全名称有多个单词，则一般取每一个单词的首字母。
								 下面是一些常见的使用习惯示例<sup>[15]</sup>：
								 <ul>
								 	<li>基本类型中，b表示byte;c或者ch表示char;d表示double，f表示float，i,j,k等等用于整形。</li>
								 	<li>布尔类型的一般用如isXXX来表示。或者isNotXXX。来表示。</li>
								 	<li>基本引用类型，s或者str表示String，o或者obj表示Object，e或者ex表示Exception</li>
								 	<li>常见简写词：如buf表示某种类型的Buffer;len表示某种东西的length。off表示依稀值，in表示输入，out表示输出。src表示某种来源，dst操作目标处。qty表示数量</li>
								 </ul>
								</p>
						   </div>
					</div><!--  end of 9.2.1 -->
					
					<div class="sub_sub_section">
						<h4 class="sub_sub_section_name">9.2.2&nbsp;使用提取方法重构改善代码结构设计</h4>
						<p>
						提取方法(Extract Method)是在开发中最常用到的重构方法之一。
						提取方法主要做的事情就是，将一定独立性，抽取到一个新的方法中，选择一个好的方法名来表达这些代码所做的工作。<sup>[16]</sup>
						提到的有好的命名的方法有很多的好处，最明显的就是，减少方法的代码行。如果一个方法，特别是在一个分支中代码太多，看起来就特别地困难。
						其次，增加在其它的方法中重用这个方法的可能性。另外，由于有良好的名字，上层代码调用这些方法就像是伪代码一样。无需要过多注释。
						</p>
						上面讲到的distanceOf()就是一个很好的提到方法的实例。在实际的开发中有更多的这样的重构。例如在实际开发中有这么一段方法
						<pre>
@Override
protected void onPostExecute(List&lt;Order&gt; result) {
	removeFragmentDialog();
	Log.d(TAG, " orderlist result    :" + result);
	if (result == null) {
		ToastUtils.showFailure(getApplicationContext(),
				R.string.msg_network_err_please_try_again);

	} else {
		mOrderListView.setAdapter(new OrderListAdapter(
		getApplicationContext(), result));
		mOrders = result;
		reverseOrders();
		updateGiveBillButtonState();
	}

}						
						</pre>
						上面是一个AsyncTask子类中的一个重写的方法：
						方法中主要的操作就是如果result为空，提示，不为空，使用返回结果处理。。
						所以简单明了的写法，应该把else子句中代码抽取出来。如下：
<pre>
private void updateAfterInitOrderList(){
	mOrderListView.setAdapter(new OrderListAdapter(
				getApplicationContext(), result));
	mOrders = result;
	reverseOrders();
	updateGiveBillButtonState();
}
</pre>
然后更新mOrderListView是会比较经常做的操作。又把这个代码抽取为方法：
<pre>
private void updateOrderListView(List&lt;Order&gt; orders){
	mOrders = orders;
	reverseOrders();
	mOrderListView.setAdapter(new OrderListAdapter(
			getApplicationContext(), orders));
}
</pre>
在后面的开发中，因为有针对Order的修改操作，这个操作在底层影响的只是mOrders中的一个元素。
所以会经常有更新操作。为了增加代码重用。所以还需要继续抽取以下代码：
<pre>
private void updateOrderListView(){
	mOrderListView.setAdapter(new OrderListAdapter(
				getApplicationContext(), mOrders));
}
</pre>
经过这个的抽取方法的重构，整个代码的可读性改善了不少。上层调用方法的代码，可以跟伪代码相比了。重构，可以改善代码的即有设计，让设计的人思维更清楚，经常重构代码有得于思考代码的设计。
写出更优秀的代码。我个人关于重构的主要经验来自于“重构：改善代码既有的设计“一书。
					</div><!--  end of 9.2.2 -->
			</div><!--  end of 9.2 -->
	       
		</section>
		
		<section class="optimize">
			<h2>10&nbsp;&nbsp;Android应用的性能优化</h2>
			<p>
			  虽然有一位计算科学的大师告诉我们"不要过早优化"，或者"优化是万恶之源"，但是对于智能设备来说（应该说对其它设备也是一样的），就应用运行得更流畅，占用更小的内存，
			  还是我们应该追求的目标。对于智能设备来说，还是有很多的设备内存比较少，而且运算处理能力也不强。
			  当然想要在性能上有较大的提升，主要还是靠设计。但是不是每个人，一开始就能很快做出优秀的设计来改善总体的性能，除了设计上的优化，改善设计，还有一些地方是比较容易做到的，
			  如代码的一些优化，布局优化。
			</p>
			<div class="sub_section">
				<h3 class="sub_section_name">10.1&nbsp;更有效的代码</h3>
				<p>由于认识的不同，及经验的问题，不同的人写出的代码也是不同的，显然很多时候性能也是不一样的。
				 当然也就存在性能比较好的代码写作习惯。下面是一些让代码更高效的示例：
				</p>
				<ul>
					<li>构造字符串对象，直接使用<code> String str = "hello";</code>，而不是<code>String str = new String("hello")；</code></li>
					<li>优先使用基本类型如boolean,int,long,double而不是Boolean,Integer,Long,Double等装箱类型</li>
					<li>使用静态工厂方法：如将一个字符串“47”转换成整型，使用Integer.valueOf("47")，而不是new Integer("47")</li>
					<li>优秀使用静态类及字段。如果一个字段是类字段，那么将其设置为<code>static final</code>。在尽可能的性能为将内部类标记为静态的，将没有使用实例变量的方法标记为静态的。</li>
					<li>优先使用List而不是数组。数组是定长，扩展性性能不好，且不支持泛型。</li>
					<li>优先使用for-each循环而不是老的for循环方式。</li>
					<li>最小化局部变量的作用域，尽量在第一次使用的时候再声明。</li>
					<li>优先使用系统类库中的方法。</li>
					<li>优先使用executors和tasks而不是线程。这是Java 5中添加的java.util.concurrent中的一个包含的一个Executor框架。</li>
					<li>对于私有内部类所访问的成员，考虑使用包级访问而不是私有访问限制。<sup>[18]</sup></li>
					<li>不要创建不必要的对象，也就是能使用基本类型值的就使用类型类型，不要使用对象。</li>
					<li>不要在类内部使用Getter和Setter</li>
					<li>对于浮点值的一些操作优先使用android.util.FloatMath类提供的方法。</li>
					<li>尽量让代码不可变，即尽可能的使用final关键词。</li>
				</ul>
				
				<p>
				 对于项目中的代码的混淆及进一步优化，可以使用Android平台推荐使用ProGuard来进行对代码进行优化及混淆。
				</p>
			</div><!--  end of 10.1 -->
			<div class="sub_section">
				<h3 class="sub_section_name">10.2&nbsp;更有效的UI</h3>
				<p>
				 也许上面所例出来的优化加起来得到的性能优化还不如一个UI优化来得直接。因为处理图形界面，对于CPU及内存的消耗非常大。
					UI的优化主要可以通过这些方面来实现。
				</p>
				<ul>
					<li>通过使用<code>&lt;include /&gt;</code>来重用UI布局。也可以看成是抽取方法的重构在布局中的应用。
					 在android布局XML文件中，可以很方便的通过include将一些可重用的部件包括进来，示例如下：
					 <pre>
&lt;include layout="@layout/yes_no_bar"/&gt;
					 </pre>
					</li>
					<li>对于同时使用<code>ImageView</code>及<code>TextView</code>的布局通过可以使用单独的一个 <code>TextView</code>来代替。关键点则是TextView可以设置其上下左右设置图像。</li>
					<li>对于嵌套层次过深的<code>LinearLayout</code>LinearLayout布局考虑使用<code>Relativelayout</code>来代替。<code>Relativelayout</code></li>
					<li>尽量使用ViewStub，ViewStub是一个惰性版本的include，可以在代码中根据需要来动态加载。</li>
					<li>在ListView及GridView等组件中，使用一个ViewHolder来存储已经初始化的列表项子View。</li>
				</ul>
				<p>
					Android SDK提供了一个名为“Hierarchy  Viewer"的工具（此工具在Eclipse ADT中可用）可以查看UI中每个部件渲染所花费的时间。
				</p>
			</div><!--  end of 10.2 -->
			
		</section>

	<section class="conclusion">
		<h2 class="section_name">结论</h2>
		<p>
		   本文介绍了无线局域网的一些技术特点，及常见实现方式如Wi-Fi技术。详细分析了无线局域网的优缺点。
		   同时本文在分析了当前最流和的Android移动操作系统之后，对于如何使用MVC模式来进行Android平台的应用开发进行了详细的分析。
		   并结合一个无线点菜系统的实现，分析了如何使用Android平台开发实际应用。完整分析了Android平台开发所需要的基本技术。
		   对于开发过程中遇到了一些设计问题进行了分析思考及提供了相应的解决方案，最后结合实际开发经验，研究了如何写出具有可读性好的
		   代码，及如何对Android应用进行基本的性能优化。
		 </p>
		<p>
		当我初始接触Android时，我非常惊讶于它优雅及完善的设计。对于国际化的支持，对于多种设备的支持，方便的资源管理方式，
		开放的系统资源，相信Android平台将会吸引越来越多的开发者加入进来。由于其开放性，也会吸引更多的厂商到Android平台上来。
		</p>
		<p>
		Android本身设计十分出色，并且整个系统软件栈是开放的。以后也能看到更多更深入的对Android系统的研究。
		本文主要是对Android应用层框架等做了比较浅显的分析。
		</p>
		<p>
		Android平台已经成熟，对于开发优秀的应用提供了各方面良好的支持，能够方便的开发出优秀的应用。
		Android平台本身也引导开发出，兼容性并具备国际化的应用。
		</p>
		<p>
			总之，一句说，android是开发者的乐土，是开发出卓越应用的基地。
		</p>
	</section>

		<section>
			<h2 class="section_name">参考文献</h2>
			<ol class="cite_list">
				<li>[1]&nbsp;<cite class="en">http://baike.baidu.com/view/32856.htm</cite></li>
				<li>[2]&nbsp;<cite class="en">http://zh.wikipedia.org/wiki/无线局域网</cite></li>
				<li>[3]&nbsp;<cite class="en">http://en.wikipedia.org/wiki/Wireless_LAN</cite></li>
				<li>[4]&nbsp;<cite class="en">http://zh.wikipedia.org/wiki/Wi-Fi</cite></li>
				<li>[5]&nbsp;<cite class="en">http://zh.wikipedia.org/wiki/蓝牙</cite></li>
				<li>[6]&nbsp;<cite class="en">http://developer.android.com/guide/basics/what-is-android.html</cite></li>
				<li>[7]&nbsp;<cite class="en">http://developer.android.com/guide/topics/fundamentals.html</cite></li>
				<li>[8]&nbsp;<cite class="en">http://developer.android.com/guide/topics/fundamentals/activities.html</cite></li>
				<li>[9]&nbsp;<cite class="en">http://developer.android.com/guide/topics/intents/intents-filters.html</cite></li>
				<li>[10]&nbsp;<cite class="en">http://developer.android.com/sdk/installing.html</cite></li>
				<li>[11]&nbsp;<cite class="en">http://developer.android.com/guide/topics/data/data-storage.html</cite></li>
				<li>[12]&nbsp;<cite class="en">http://tech.ifeng.com/telecom/detail_2012_05/15/14543183_0.shtml</cite></li>
				<li>[13]&nbsp;<cite class="en">http://zh.wikipedia.org/wiki/Android</cite></li>
				<li  class="long_cite"><span class="long_cite">[14]&nbsp;</span><cite class="zh">(美)奥克斯(Oaks,S.)，（美）王(Wong.H)著.Java线程：第三版（O'Reilly Taiwan公司编译)[M].南京:东南大学出版社,2006.3：188~189</cite></li>
				<li  class="long_cite"><span class="long_cite">[15]&nbsp;</span><cite class="zh">(美)高斯林(Goasling,J.)，et al.Java编程规范（第三版）（陈宗斌，沈金河译)[M].北京:中国电力出版社,2006.7：114~114</cite></li>
				<li  class="long_cite"><span class="long_cite">[16]&nbsp;</span><cite class="zh">(美)福勒(Flowler,M.)著.重构：改善代码即有设计：英文注释版（陈宗斌，沈金河译)[M].北京:人民邮电出版社,2008.2：110~111</cite></li>
				<li >[17]&nbsp;<cite class="en">http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html</cite></li>
				<li>[18]&nbsp;<cite class="en">http://developer.android.com/guide/practices/design/performance.html</cite></li>
				<li>[19]&nbsp;<cite class="en">http://zh.wikipedia.org/wiki/MVC</cite></li>
				<li class="long_cite"><span class="long_cite">[20]&nbsp;</span><cite class="en">Beck,Kent.eXtreme Programming eXplained:Embrace Change.Reading,Mass.:Addison-Wesley,2000.</cite></li>
				<li class="long_cite"><span class="long_cite">[21]&nbsp;</span><cite class="en">Gosling,James,Bill Joy,and Guy Steele.The Java Language Specification,Second Edition.Boston,Mass:Addison-Wesley,2000.</cite></li>
				<li  class="long_cite"><span class="long_cite">[22]&nbsp;</span><cite class="zh">柯元旦著.Android内核剖析[M].北京:电子工业出版社,2011.9：268~269</cite></li>
				<li  class="long_cite"><span class="long_cite">[23]&nbsp;</span><cite class="zh">杨丰盛著.Android技术内幕[M].北京:机械工业出版社,2011.5：244~245</cite></li>
				
			</ol>
			<section>
		<section class="acknowledgements">
			<h2 class="section_name">致谢</h2>
			<p>感谢父母让我一直读到了大学，我只是一个普通的人，但是父母却将我培养成人才了！</p>
			<p>感谢我弟，我哥为我们的家所做出牺牲！他们可以读更多书的，但是把机会让给了我！我感动同时愧疚！</p>
			<p>感谢在我身边陪我走过这么多看岁月的同学，朋友，谢谢你们。</p>
			<p>感谢桂电，我对这个学校很满意！</p>
			<p>感谢教育过我的老师，是他们照亮了我求知的道路。</p>
			<p>最后，要特别感谢我的指导老师，王虎寅老师，没有它的指导，就没有我的这篇论文。</p>
		</section>
		<section class="appendix">
			<h2 class="section_name">附录</h2>
				<div data-role="collapsible" data-theme="a">
					<h3>附录一</h3>
					<p>
					 一个简单的TCP连接池，说明：里面的TcpTransport其实就是对Socket对象的简单封装的类。
					</p>
					<pre>
public class TcpTransportPool {
	private static final String TAG = "TcpTransportPool";

	private final String host;
	private final int port;
	private static final int MAX_SIZE = 10;
	private static final int MIN_SIZE = 2;
	private final List&lt;TcpTransport&gt; pool = new ArrayList&lt;TcpTransport&gt;(8);

	public TcpTransportPool(String host, int port) {
		this.host = host;
		this.port = port;
	}

	public void initPool() {

		TcpTransport connection;
		try {
			connection = new TcpTransport(host, port);
		} catch (IOException e) {
			e.printStackTrace();
			return;
		}

		while (pool.size() < MIN_SIZE) {
			pool.add(pool.size(), connection);
			try {
				connection = new TcpTransport(host, port);
			} catch (IOException e) {
				e.printStackTrace();
				return;
			}
		}

	}

	public synchronized TcpTransport getTransport() {
		if (pool.size() > 0 ) {
			return pool.remove(0);
		}
		Log.d(TAG, "pool size:" + pool.size() + " need more");
		try {
			return new TcpTransport(host, port);
		} catch (IOException e) {
				e.printStackTrace();
		}
		return null;
	}

	public synchronized void recyleTransport(TcpTransport con) {
		if (pool.size() > MAX_SIZE)
			return;
		pool.add(con);
	}

	public void destroy() {
		for (TcpTransport con : pool) {
			if (con != null) {
				con.disconnect();
			}
		}
		pool.clear();
	}

}					
					</pre>
				</div><!--  end of appendix 1 -->
				
			<div data-role="collapsible" data-theme="a">
			<h3>附录二</h3>
				<p>一个简单的Toast实用工具类</p>
				<pre>
public class ToastUtils {
	public static void showLong(Context context, String message) {
		show(context, message, Toast.LENGTH_LONG);
	}

	public static void showShort(Context context, String message) {
		show(context, message, Toast.LENGTH_SHORT);
	}

	public static void showLong(Context context, int textId) {
		show(context, textId, Toast.LENGTH_LONG);
	}

	public static void showShort(Context context, int textId) {
		show(context, textId, Toast.LENGTH_SHORT);
	}

	public static void show(Context context, String text, int duration) {
		Toast toast = Toast.makeText(context, text, duration);
		toast.setGravity(Gravity.CENTER, 80, 80);
		toast.show();
	}

	public static void show(Context context, int textId, int duration) {
		show(context,context.getString(textId),duration);
	}

	public static void showSuccess(Context context, int textId) {
		showIconToast(context, context.getString(textId),
				R.drawable.ic_success, R.color.holo_blue, Toast.LENGTH_SHORT);
	}

	public static void showFailure(Context context, int textId) {
		showIconToast(context, context.getString(textId),
				R.drawable.ic_failure, R.color.warn, Toast.LENGTH_LONG);
	}

	public static void showFailure(Context context, String text) {
		showIconToast(context, text, R.drawable.ic_failure, R.color.warn,
				Toast.LENGTH_LONG);
	}

	public static void showIconToast(Context context, String textId,
			int iconId, int colorId, int duration) {
		LayoutInflater inflater = (LayoutInflater) context
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		View layout = inflater.inflate(R.layout.toast, null);
		((TextView) layout).setText(textId);
		((TextView) layout).setTextColor(context.getResources().getColor(
				colorId));
		((TextView) layout).setCompoundDrawablesWithIntrinsicBounds(iconId, 0,
				0, 0);
		Toast toast = new Toast(context);
		toast.setGravity(Gravity.CENTER_VERTICAL, 0, -100);
		toast.setDuration(duration);
		toast.setView(layout);
		toast.show();
	}

}

				</pre>
				
		</div>
		
		<div class="">
			<h3>附录三</h3>
				<p>菜品格子中的菜品项而已XML文件menu_item.xml内容</p>
				<pre>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="60sp"
    android:layout_gravity="center"
    android:background="@drawable/bg_menu"
    android:gravity="center"
    android:orientation="vertical" &gt;

    &lt;TextView
        android:id="@+id/menu_name_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:gravity="center"
        android:maxLines="1"
        android:text=""
        android:textColor="#000"
        android:textSize="20sp" /&gt;

    &lt;RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" &gt;

        &lt;TextView
            android:id="@+id/menu_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:gravity="right|bottom"
            android:paddingRight="3dp"
            android:text=""
            android:textColor="#3e6d8e"
            android:textSize="12sp"
            android:textStyle="bold" /&gt;

        &lt;TextView
            android:id="@+id/menu_name_2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:layout_below="@id/menu_name_zh"
            android:layout_marginLeft="5dp"
            android:layout_toLeftOf="@id/menu_price"
            android:ellipsize="end"
            android:gravity="center"
            android:maxLines="1"
            android:text=""
            android:textColor="#000"
            android:textSize="20sp" /&gt;
    &lt;/RelativeLayout&gt;

&lt;/LinearLayout&gt;				
				</pre>
		</div>
		<div class="">
			<h3>附录四</h3>
				<p>菜品格子适配器类</p>
				<pre>
private static class MenuxAdapter extends BaseAdapter {
	private final List<Menux> mData;
	private final LayoutInflater mInflater;
	public MenuxAdapter(Context context, List<Menux> data) {
	mData = data;
	mInflater = (LayoutInflater) context
			.getSystemService(LAYOUT_INFLATER_SERVICE);
	}
	@Override
	public int getCount() {
		return mData.size();
	}
	@Override
	public Object getItem(int position) {
		return mData.get(position);
	}
	@Override
	public long getItemId(int position) {
		return position;
	}
	@Override
	public View getView(int position, View convertView,
						 ViewGroup parent) {
		MenuxViewHolder holder;
		if (convertView == null) {
		convertView = mInflater
			.inflate(R.layout.menu_item, null);
		holder = new MenuxViewHolder();
		holder.name1 = (TextView) convertView
				.findViewById(R.id.menu_name_1);
		holder.name2 = (TextView) convertView
				.findViewById(R.id.menu_name_2);
		holder.price = (TextView) convertView
				.findViewById(R.id.menu_price);
		convertView.setTag(holder);
		} else {
		holder = (MenuxViewHolder) convertView.getTag();
		}
		Menux menux = mData.get(position);
		String name = "";
		if (DiSettings.PREF_LANG_EN
		.equals(DiApplication.getPrefMenuLang())) {
			name = menux.prefEn();
		} else {
			name = menux.prefCh();
		}
		holder.price.setText(menux.getPrice());
		String names[] = name.split(",", 2);
		if (names.length == 1) {
			holder.name1.setVisibility(View.GONE);
			holder.name2.setMaxLines(2);
			holder.name2.setText(names[0]);
		} else {
			holder.name1.setText(names[0].trim());
			holder.name2.setText(names[1].trim());
		}
		convertView.setMinimumHeight(2 *
		 holder.name1.getLineHeight());
		return convertView;
	}
	static class MenuxViewHolder {
		TextView name1;
		TextView name2;
		TextView price;
	}

}			
				</pre>
		</div>
		</section><!--  end of section appendix -->
	</div>


	</div>
	<!--  end of article  -->
</body>
</html>
